summaryrefslogtreecommitdiffstats
path: root/WebCore/html
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/html')
-rw-r--r--WebCore/html/FTPDirectoryDocument.cpp451
-rw-r--r--WebCore/html/FTPDirectoryDocument.h48
-rw-r--r--WebCore/html/HTMLEmbedElement.cpp46
-rw-r--r--WebCore/html/HTMLEmbedElement.h6
-rw-r--r--WebCore/html/HTMLImageElement.cpp18
-rw-r--r--WebCore/html/HTMLInputElement.cpp28
-rw-r--r--WebCore/html/HTMLInputElement.h2
-rw-r--r--WebCore/html/HTMLLinkElement.cpp6
-rw-r--r--WebCore/html/HTMLMediaElement.cpp263
-rw-r--r--WebCore/html/HTMLMediaElement.h14
-rw-r--r--WebCore/html/HTMLObjectElement.cpp168
-rw-r--r--WebCore/html/HTMLObjectElement.h10
-rw-r--r--WebCore/html/HTMLPlugInImageElement.cpp58
-rw-r--r--WebCore/html/HTMLPlugInImageElement.h20
-rw-r--r--WebCore/html/HTMLSelectElement.cpp11
-rw-r--r--WebCore/html/HTMLSelectElement.h2
-rw-r--r--WebCore/html/HTMLViewSourceDocument.cpp12
-rw-r--r--WebCore/html/HTMLViewSourceDocument.h3
-rw-r--r--WebCore/html/ImageDocument.cpp414
-rw-r--r--WebCore/html/ImageDocument.h76
-rw-r--r--WebCore/html/MediaDocument.cpp215
-rw-r--r--WebCore/html/MediaDocument.h61
-rw-r--r--WebCore/html/PluginDocument.cpp161
-rw-r--r--WebCore/html/PluginDocument.h54
-rw-r--r--WebCore/html/TextDocument.cpp44
-rw-r--r--WebCore/html/TextDocument.h47
-rw-r--r--WebCore/html/canvas/ArrayBufferView.cpp28
-rw-r--r--WebCore/html/canvas/ArrayBufferView.h4
-rw-r--r--WebCore/html/canvas/CanvasRenderingContext.cpp12
-rw-r--r--WebCore/html/canvas/CanvasRenderingContext.h13
-rwxr-xr-x[-rw-r--r--]WebCore/html/canvas/CanvasRenderingContext2D.cpp91
-rw-r--r--WebCore/html/canvas/CanvasRenderingContext2D.h26
-rw-r--r--WebCore/html/canvas/TypedArrayBase.h10
-rw-r--r--WebCore/html/canvas/WebGLRenderingContext.cpp5
-rw-r--r--WebCore/html/canvas/WebGLRenderingContext.h6
-rw-r--r--WebCore/html/parser/CSSPreloadScanner.cpp4
-rw-r--r--WebCore/html/parser/HTMLConstructionSite.cpp13
-rw-r--r--WebCore/html/parser/HTMLDocumentParser.cpp65
-rw-r--r--WebCore/html/parser/HTMLDocumentParser.h7
-rw-r--r--WebCore/html/parser/HTMLInputStream.h (renamed from WebCore/html/HTMLInputStream.h)0
-rw-r--r--WebCore/html/parser/HTMLPreloadScanner.cpp10
-rw-r--r--WebCore/html/parser/HTMLScriptRunner.cpp55
-rw-r--r--WebCore/html/parser/HTMLScriptRunner.h4
-rw-r--r--WebCore/html/parser/HTMLTokenizer.cpp4
-rw-r--r--WebCore/html/parser/HTMLTreeBuilder.cpp5
-rw-r--r--WebCore/html/parser/HTMLTreeBuilder.h2
-rw-r--r--WebCore/html/parser/HTMLViewSourceParser.h7
-rw-r--r--WebCore/html/parser/TextDocumentParser.cpp72
-rw-r--r--WebCore/html/parser/TextDocumentParser.h52
-rw-r--r--WebCore/html/parser/TextViewSourceParser.cpp43
-rw-r--r--WebCore/html/parser/TextViewSourceParser.h47
51 files changed, 2654 insertions, 169 deletions
diff --git a/WebCore/html/FTPDirectoryDocument.cpp b/WebCore/html/FTPDirectoryDocument.cpp
new file mode 100644
index 0000000..6475ea9
--- /dev/null
+++ b/WebCore/html/FTPDirectoryDocument.cpp
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if ENABLE(FTPDIR)
+#include "FTPDirectoryDocument.h"
+
+#include "CharacterNames.h"
+#include "HTMLDocumentParser.h"
+#include "HTMLNames.h"
+#include "HTMLTableElement.h"
+#include "LocalizedStrings.h"
+#include "Logging.h"
+#include "FTPDirectoryParser.h"
+#include "SegmentedString.h"
+#include "Settings.h"
+#include "SharedBuffer.h"
+#include "Text.h"
+
+#include <wtf/text/CString.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/StdLibExtras.h>
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+class FTPDirectoryDocumentParser : public HTMLDocumentParser {
+public:
+ static PassRefPtr<FTPDirectoryDocumentParser> create(HTMLDocument* document)
+ {
+ return adoptRef(new FTPDirectoryDocumentParser(document));
+ }
+
+ virtual void append(const SegmentedString&);
+ virtual void finish();
+
+ virtual bool isWaitingForScripts() const { return false; }
+
+ inline void checkBuffer(int len = 10)
+ {
+ if ((m_dest - m_buffer) > m_size - len) {
+ // Enlarge buffer
+ int newSize = max(m_size * 2, m_size + len);
+ int oldOffset = m_dest - m_buffer;
+ m_buffer = static_cast<UChar*>(fastRealloc(m_buffer, newSize * sizeof(UChar)));
+ m_dest = m_buffer + oldOffset;
+ m_size = newSize;
+ }
+ }
+
+private:
+ FTPDirectoryDocumentParser(HTMLDocument*);
+
+ // The parser will attempt to load the document template specified via the preference
+ // Failing that, it will fall back and create the basic document which will have a minimal
+ // table for presenting the FTP directory in a useful manner
+ bool loadDocumentTemplate();
+ void createBasicDocument();
+
+ void parseAndAppendOneLine(const String&);
+ void appendEntry(const String& name, const String& size, const String& date, bool isDirectory);
+ PassRefPtr<Element> createTDForFilename(const String&);
+
+ RefPtr<HTMLTableElement> m_tableElement;
+
+ bool m_skipLF;
+ bool m_parsedTemplate;
+
+ int m_size;
+ UChar* m_buffer;
+ UChar* m_dest;
+ String m_carryOver;
+
+ ListState m_listState;
+};
+
+FTPDirectoryDocumentParser::FTPDirectoryDocumentParser(HTMLDocument* document)
+ : HTMLDocumentParser(document, false)
+ , m_skipLF(false)
+ , m_parsedTemplate(false)
+ , m_size(254)
+ , m_buffer(static_cast<UChar*>(fastMalloc(sizeof(UChar) * m_size)))
+ , m_dest(m_buffer)
+{
+}
+
+void FTPDirectoryDocumentParser::appendEntry(const String& filename, const String& size, const String& date, bool isDirectory)
+{
+ ExceptionCode ec;
+
+ RefPtr<Element> rowElement = m_tableElement->insertRow(-1, ec);
+ rowElement->setAttribute("class", "ftpDirectoryEntryRow", ec);
+
+ RefPtr<Element> element = document()->createElement(tdTag, false);
+ element->appendChild(Text::create(document(), String(&noBreakSpace, 1)), ec);
+ if (isDirectory)
+ element->setAttribute("class", "ftpDirectoryIcon ftpDirectoryTypeDirectory", ec);
+ else
+ element->setAttribute("class", "ftpDirectoryIcon ftpDirectoryTypeFile", ec);
+ rowElement->appendChild(element, ec);
+
+ element = createTDForFilename(filename);
+ element->setAttribute("class", "ftpDirectoryFileName", ec);
+ rowElement->appendChild(element, ec);
+
+ element = document()->createElement(tdTag, false);
+ element->appendChild(Text::create(document(), date), ec);
+ element->setAttribute("class", "ftpDirectoryFileDate", ec);
+ rowElement->appendChild(element, ec);
+
+ element = document()->createElement(tdTag, false);
+ element->appendChild(Text::create(document(), size), ec);
+ element->setAttribute("class", "ftpDirectoryFileSize", ec);
+ rowElement->appendChild(element, ec);
+}
+
+PassRefPtr<Element> FTPDirectoryDocumentParser::createTDForFilename(const String& filename)
+{
+ ExceptionCode ec;
+
+ String fullURL = document()->baseURL().string();
+ if (fullURL[fullURL.length() - 1] == '/')
+ fullURL.append(filename);
+ else
+ fullURL.append("/" + filename);
+
+ RefPtr<Element> anchorElement = document()->createElement(aTag, false);
+ anchorElement->setAttribute("href", fullURL, ec);
+ anchorElement->appendChild(Text::create(document(), filename), ec);
+
+ RefPtr<Element> tdElement = document()->createElement(tdTag, false);
+ tdElement->appendChild(anchorElement, ec);
+
+ return tdElement.release();
+}
+
+static String processFilesizeString(const String& size, bool isDirectory)
+{
+ if (isDirectory)
+ return "--";
+
+ bool valid;
+ int64_t bytes = size.toUInt64(&valid);
+ if (!valid)
+ return unknownFileSizeText();
+
+ if (bytes < 1000000)
+ return String::format("%.2f KB", static_cast<float>(bytes)/1000);
+
+ if (bytes < 1000000000)
+ return String::format("%.2f MB", static_cast<float>(bytes)/1000000);
+
+ return String::format("%.2f GB", static_cast<float>(bytes)/1000000000);
+}
+
+static bool wasLastDayOfMonth(int year, int month, int day)
+{
+ static int lastDays[] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ if (month < 0 || month > 11)
+ return false;
+
+ if (month == 2) {
+ if (year % 4 == 0 && (year % 100 || year % 400 == 0)) {
+ if (day == 29)
+ return true;
+ return false;
+ }
+
+ if (day == 28)
+ return true;
+ return false;
+ }
+
+ return lastDays[month] == day;
+}
+
+static String processFileDateString(const FTPTime& fileTime)
+{
+ // FIXME: Need to localize this string?
+
+ String timeOfDay;
+
+ if (!(fileTime.tm_hour == 0 && fileTime.tm_min == 0 && fileTime.tm_sec == 0)) {
+ int hour = fileTime.tm_hour;
+ ASSERT(hour >= 0 && hour < 24);
+
+ if (hour < 12) {
+ if (hour == 0)
+ hour = 12;
+ timeOfDay = String::format(", %i:%02i AM", hour, fileTime.tm_min);
+ } else {
+ hour = hour - 12;
+ if (hour == 0)
+ hour = 12;
+ timeOfDay = String::format(", %i:%02i PM", hour, fileTime.tm_min);
+ }
+ }
+
+ // If it was today or yesterday, lets just do that - but we have to compare to the current time
+ struct tm now;
+ time_t now_t = time(NULL);
+ getLocalTime(&now_t, &now);
+
+ // localtime does "year = current year - 1900", compensate for that for readability and comparison purposes
+ now.tm_year += 1900;
+
+ if (fileTime.tm_year == now.tm_year) {
+ if (fileTime.tm_mon == now.tm_mon) {
+ if (fileTime.tm_mday == now.tm_mday)
+ return "Today" + timeOfDay;
+ if (fileTime.tm_mday == now.tm_mday - 1)
+ return "Yesterday" + timeOfDay;
+ }
+
+ if (now.tm_mday == 1 && (now.tm_mon == fileTime.tm_mon + 1 || (now.tm_mon == 0 && fileTime.tm_mon == 11)) &&
+ wasLastDayOfMonth(fileTime.tm_year, fileTime.tm_mon, fileTime.tm_mday))
+ return "Yesterday" + timeOfDay;
+ }
+
+ if (fileTime.tm_year == now.tm_year - 1 && fileTime.tm_mon == 12 && fileTime.tm_mday == 31 && now.tm_mon == 1 && now.tm_mday == 1)
+ return "Yesterday" + timeOfDay;
+
+ static const char* months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "???" };
+
+ int month = fileTime.tm_mon;
+ if (month < 0 || month > 11)
+ month = 12;
+
+ String dateString;
+
+ if (fileTime.tm_year > -1)
+ dateString = String::format("%s %i, %i", months[month], fileTime.tm_mday, fileTime.tm_year);
+ else
+ dateString = String::format("%s %i, %i", months[month], fileTime.tm_mday, now.tm_year);
+
+ return dateString + timeOfDay;
+}
+
+void FTPDirectoryDocumentParser::parseAndAppendOneLine(const String& inputLine)
+{
+ ListResult result;
+ CString latin1Input = inputLine.latin1();
+
+ FTPEntryType typeResult = parseOneFTPLine(latin1Input.data(), m_listState, result);
+
+ // FTPMiscEntry is a comment or usage statistic which we don't care about, and junk is invalid data - bail in these 2 cases
+ if (typeResult == FTPMiscEntry || typeResult == FTPJunkEntry)
+ return;
+
+ String filename(result.filename, result.filenameLength);
+ if (result.type == FTPDirectoryEntry) {
+ filename.append("/");
+
+ // We have no interest in linking to "current directory"
+ if (filename == "./")
+ return;
+ }
+
+ LOG(FTP, "Appending entry - %s, %s", filename.ascii().data(), result.fileSize.ascii().data());
+
+ appendEntry(filename, processFilesizeString(result.fileSize, result.type == FTPDirectoryEntry), processFileDateString(result.modifiedTime), result.type == FTPDirectoryEntry);
+}
+
+static inline PassRefPtr<SharedBuffer> createTemplateDocumentData(Settings* settings)
+{
+ RefPtr<SharedBuffer> buffer = 0;
+ if (settings)
+ buffer = SharedBuffer::createWithContentsOfFile(settings->ftpDirectoryTemplatePath());
+ if (buffer)
+ LOG(FTP, "Loaded FTPDirectoryTemplate of length %i\n", buffer->size());
+ return buffer.release();
+}
+
+bool FTPDirectoryDocumentParser::loadDocumentTemplate()
+{
+ DEFINE_STATIC_LOCAL(RefPtr<SharedBuffer>, templateDocumentData, (createTemplateDocumentData(document()->settings())));
+ // FIXME: Instead of storing the data, we'd rather actually parse the template data into the template Document once,
+ // store that document, then "copy" it whenever we get an FTP directory listing. There are complexities with this
+ // approach that make it worth putting this off.
+
+ if (!templateDocumentData) {
+ LOG_ERROR("Could not load templateData");
+ return false;
+ }
+
+ HTMLDocumentParser::insert(String(templateDocumentData->data(), templateDocumentData->size()));
+
+ RefPtr<Element> tableElement = document()->getElementById("ftpDirectoryTable");
+ if (!tableElement)
+ LOG_ERROR("Unable to find element by id \"ftpDirectoryTable\" in the template document.");
+ else if (!tableElement->hasTagName(tableTag))
+ LOG_ERROR("Element of id \"ftpDirectoryTable\" is not a table element");
+ else
+ m_tableElement = static_cast<HTMLTableElement*>(tableElement.get());
+
+ // Bail if we found the table element
+ if (m_tableElement)
+ return true;
+
+ // Otherwise create one manually
+ tableElement = document()->createElement(tableTag, false);
+ m_tableElement = static_cast<HTMLTableElement*>(tableElement.get());
+ ExceptionCode ec;
+ m_tableElement->setAttribute("id", "ftpDirectoryTable", ec);
+
+ // If we didn't find the table element, lets try to append our own to the body
+ // If that fails for some reason, cram it on the end of the document as a last
+ // ditch effort
+ if (Element* body = document()->body())
+ body->appendChild(m_tableElement, ec);
+ else
+ document()->appendChild(m_tableElement, ec);
+
+ return true;
+}
+
+void FTPDirectoryDocumentParser::createBasicDocument()
+{
+ LOG(FTP, "Creating a basic FTP document structure as no template was loaded");
+
+ // FIXME: Make this "basic document" more acceptable
+
+ RefPtr<Element> bodyElement = document()->createElement(bodyTag, false);
+
+ ExceptionCode ec;
+ document()->appendChild(bodyElement, ec);
+
+ RefPtr<Element> tableElement = document()->createElement(tableTag, false);
+ m_tableElement = static_cast<HTMLTableElement*>(tableElement.get());
+ m_tableElement->setAttribute("id", "ftpDirectoryTable", ec);
+
+ bodyElement->appendChild(m_tableElement, ec);
+}
+
+void FTPDirectoryDocumentParser::append(const SegmentedString& source)
+{
+ // Make sure we have the table element to append to by loading the template set in the pref, or
+ // creating a very basic document with the appropriate table
+ if (!m_tableElement) {
+ if (!loadDocumentTemplate())
+ createBasicDocument();
+ ASSERT(m_tableElement);
+ }
+
+ bool foundNewLine = false;
+
+ m_dest = m_buffer;
+ SegmentedString str = source;
+ while (!str.isEmpty()) {
+ UChar c = *str;
+
+ if (c == '\r') {
+ *m_dest++ = '\n';
+ foundNewLine = true;
+ // possibly skip an LF in the case of an CRLF sequence
+ m_skipLF = true;
+ } else if (c == '\n') {
+ if (!m_skipLF)
+ *m_dest++ = c;
+ else
+ m_skipLF = false;
+ } else {
+ *m_dest++ = c;
+ m_skipLF = false;
+ }
+
+ str.advance();
+
+ // Maybe enlarge the buffer
+ checkBuffer();
+ }
+
+ if (!foundNewLine) {
+ m_dest = m_buffer;
+ return;
+ }
+
+ UChar* start = m_buffer;
+ UChar* cursor = start;
+
+ while (cursor < m_dest) {
+ if (*cursor == '\n') {
+ m_carryOver.append(String(start, cursor - start));
+ LOG(FTP, "%s", m_carryOver.ascii().data());
+ parseAndAppendOneLine(m_carryOver);
+ m_carryOver = String();
+
+ start = ++cursor;
+ } else
+ cursor++;
+ }
+
+ // Copy the partial line we have left to the carryover buffer
+ if (cursor - start > 1)
+ m_carryOver.append(String(start, cursor - start - 1));
+}
+
+void FTPDirectoryDocumentParser::finish()
+{
+ // Possible the last line in the listing had no newline, so try to parse it now
+ if (!m_carryOver.isEmpty()) {
+ parseAndAppendOneLine(m_carryOver);
+ m_carryOver = String();
+ }
+
+ m_tableElement = 0;
+ fastFree(m_buffer);
+
+ HTMLDocumentParser::finish();
+}
+
+FTPDirectoryDocument::FTPDirectoryDocument(Frame* frame, const KURL& url)
+ : HTMLDocument(frame, url)
+{
+#ifndef NDEBUG
+ LogFTP.state = WTFLogChannelOn;
+#endif
+}
+
+PassRefPtr<DocumentParser> FTPDirectoryDocument::createParser()
+{
+ return FTPDirectoryDocumentParser::create(this);
+}
+
+}
+
+#endif // ENABLE(FTPDIR)
diff --git a/WebCore/html/FTPDirectoryDocument.h b/WebCore/html/FTPDirectoryDocument.h
new file mode 100644
index 0000000..e7e52f7
--- /dev/null
+++ b/WebCore/html/FTPDirectoryDocument.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FTPDirectoryDocument_h
+#define FTPDirectoryDocument_h
+
+#include "HTMLDocument.h"
+
+namespace WebCore {
+
+class DOMImplementation;
+
+class FTPDirectoryDocument : public HTMLDocument {
+public:
+ static PassRefPtr<FTPDirectoryDocument> create(Frame* frame, const KURL& url)
+ {
+ return adoptRef(new FTPDirectoryDocument(frame, url));
+ }
+
+private:
+ FTPDirectoryDocument(Frame*, const KURL&);
+ virtual PassRefPtr<DocumentParser> createParser();
+};
+
+} // namespace WebCore
+
+#endif // FTPDirectoryDocument_h
diff --git a/WebCore/html/HTMLEmbedElement.cpp b/WebCore/html/HTMLEmbedElement.cpp
index eeb28e7..e88ee81 100644
--- a/WebCore/html/HTMLEmbedElement.cpp
+++ b/WebCore/html/HTMLEmbedElement.cpp
@@ -120,6 +120,52 @@ void HTMLEmbedElement::parseMappedAttribute(Attribute* attr)
HTMLPlugInImageElement::parseMappedAttribute(attr);
}
+void HTMLEmbedElement::parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues)
+{
+ NamedNodeMap* attributes = this->attributes(true);
+ if (!attributes)
+ return;
+
+ for (unsigned i = 0; i < attributes->length(); ++i) {
+ Attribute* it = attributes->attributeItem(i);
+ paramNames.append(it->localName().string());
+ paramValues.append(it->value().string());
+ }
+}
+
+// FIXME: This should be unified with HTMLObjectElement::updateWidget and
+// moved down into HTMLPluginImageElement.cpp
+void HTMLEmbedElement::updateWidget(bool onlyCreateNonNetscapePlugins)
+{
+ ASSERT(!renderEmbeddedObject()->pluginCrashedOrWasMissing());
+ // FIXME: We should ASSERT(needsWidgetUpdate()), but currently
+ // FrameView::updateWidget() calls updateWidget(false) without checking if
+ // the widget actually needs updating!
+ setNeedsWidgetUpdate(false);
+
+ if (m_url.isEmpty() && m_serviceType.isEmpty())
+ return;
+
+ // Note these pass m_url and m_serviceType to allow better code sharing with
+ // <object> which modifies url and serviceType before calling these.
+ if (!allowedToLoadFrameURL(m_url))
+ return;
+ if (onlyCreateNonNetscapePlugins && wouldLoadAsNetscapePlugin(m_url, m_serviceType))
+ return;
+
+ // FIXME: These should be joined into a PluginParameters class.
+ Vector<String> paramNames;
+ Vector<String> paramValues;
+ parametersForPlugin(paramNames, paramValues);
+
+ if (!dispatchBeforeLoadEvent(m_url))
+ return;
+
+ SubframeLoader* loader = document()->frame()->loader()->subframeLoader();
+ // FIXME: beforeLoad could have detached the renderer! Just like in the <object> case above.
+ loader->requestObject(this, m_url, getAttribute(nameAttr), m_serviceType, paramNames, paramValues);
+}
+
bool HTMLEmbedElement::rendererIsNeeded(RenderStyle* style)
{
if (isImageType())
diff --git a/WebCore/html/HTMLEmbedElement.h b/WebCore/html/HTMLEmbedElement.h
index e27b717..70eb0dc 100644
--- a/WebCore/html/HTMLEmbedElement.h
+++ b/WebCore/html/HTMLEmbedElement.h
@@ -41,13 +41,17 @@ private:
virtual void insertedIntoDocument();
virtual void removedFromDocument();
virtual void attributeChanged(Attribute*, bool preserveDecls = false);
-
+
virtual bool isURLAttribute(Attribute*) const;
virtual const QualifiedName& imageSourceAttributeName() const;
virtual RenderWidget* renderWidgetForJSBindings() const;
+ virtual void updateWidget(bool onlyCreateNonNetscapePlugins);
+
virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const;
+
+ void parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues);
};
}
diff --git a/WebCore/html/HTMLImageElement.cpp b/WebCore/html/HTMLImageElement.cpp
index b7ece78..d223b1e 100644
--- a/WebCore/html/HTMLImageElement.cpp
+++ b/WebCore/html/HTMLImageElement.cpp
@@ -267,10 +267,8 @@ int HTMLImageElement::width(bool ignorePendingStylesheets) const
return width;
// if the image is available, use its width
- if (m_imageLoader.image()) {
- float zoomFactor = document()->view() ? document()->view()->pageZoomFactor() : 1.0f;
- return m_imageLoader.image()->imageSize(zoomFactor).width();
- }
+ if (m_imageLoader.image())
+ return m_imageLoader.image()->imageSize(1.0f).width();
}
if (ignorePendingStylesheets)
@@ -278,7 +276,8 @@ int HTMLImageElement::width(bool ignorePendingStylesheets) const
else
document()->updateLayout();
- return renderBox() ? renderBox()->contentWidth() : 0;
+ RenderBox* box = renderBox();
+ return box ? adjustForAbsoluteZoom(box->contentWidth(), box) : 0;
}
int HTMLImageElement::height(bool ignorePendingStylesheets) const
@@ -291,10 +290,8 @@ int HTMLImageElement::height(bool ignorePendingStylesheets) const
return height;
// if the image is available, use its height
- if (m_imageLoader.image()) {
- float zoomFactor = document()->view() ? document()->view()->pageZoomFactor() : 1.0f;
- return m_imageLoader.image()->imageSize(zoomFactor).height();
- }
+ if (m_imageLoader.image())
+ return m_imageLoader.image()->imageSize(1.0f).height();
}
if (ignorePendingStylesheets)
@@ -302,7 +299,8 @@ int HTMLImageElement::height(bool ignorePendingStylesheets) const
else
document()->updateLayout();
- return renderBox() ? renderBox()->contentHeight() : 0;
+ RenderBox* box = renderBox();
+ return box ? adjustForAbsoluteZoom(box->contentHeight(), box) : 0;
}
int HTMLImageElement::naturalWidth() const
diff --git a/WebCore/html/HTMLInputElement.cpp b/WebCore/html/HTMLInputElement.cpp
index c2e5416..5ff979b 100644
--- a/WebCore/html/HTMLInputElement.cpp
+++ b/WebCore/html/HTMLInputElement.cpp
@@ -263,7 +263,8 @@ bool HTMLInputElement::typeMismatch(const String& value) const
case COLOR:
return !isValidColorString(value);
case NUMBER:
- return !parseToDoubleForNumberType(value, 0);
+ ASSERT(parseToDoubleForNumberType(value, 0));
+ return false;
case URL:
return !KURL(KURL(), value).isValid();
case EMAIL: {
@@ -830,6 +831,14 @@ void HTMLInputElement::handleFocusEvent()
void HTMLInputElement::handleBlurEvent()
{
+ if (inputType() == NUMBER) {
+ // Reset the renderer value, which might be unmatched with the element value.
+ setFormControlValueMatchesRenderer(false);
+ // We need to reset the renderer value explicitly because an unacceptable
+ // renderer value should be purged before style calculation.
+ if (renderer())
+ renderer()->updateFromElement();
+ }
InputElement::dispatchBlurEvent(this, this);
}
@@ -2273,7 +2282,7 @@ void HTMLInputElement::defaultEventHandler(Event* evt)
&& evt->isKeyboardEvent()
&& focused()
&& document()->frame()
- && document()->frame()->doTextFieldCommandFromEvent(this, static_cast<KeyboardEvent*>(evt))) {
+ && document()->frame()->editor()->doTextFieldCommandFromEvent(this, static_cast<KeyboardEvent*>(evt))) {
evt->setDefaultHandled();
return;
}
@@ -2676,8 +2685,18 @@ FileList* HTMLInputElement::files()
return m_fileList.get();
}
+bool HTMLInputElement::isAcceptableValue(const String& proposedValue) const
+{
+ if (inputType() != NUMBER)
+ return true;
+ return proposedValue.isEmpty() || parseToDoubleForNumberType(proposedValue, 0);
+}
+
String HTMLInputElement::sanitizeValue(const String& proposedValue) const
{
+ if (inputType() == NUMBER)
+ return parseToDoubleForNumberType(proposedValue, 0) ? proposedValue : String();
+
if (isTextField())
return InputElement::sanitizeValueForTextField(this, proposedValue);
@@ -2690,6 +2709,11 @@ String HTMLInputElement::sanitizeValue(const String& proposedValue) const
return proposedValue;
}
+bool HTMLInputElement::hasUnacceptableValue() const
+{
+ return inputType() == NUMBER && renderer() && !isAcceptableValue(toRenderTextControl(renderer())->text());
+}
+
bool HTMLInputElement::needsActivationCallback()
{
return inputType() == PASSWORD || m_autocomplete == Off;
diff --git a/WebCore/html/HTMLInputElement.h b/WebCore/html/HTMLInputElement.h
index 657b468..e023796 100644
--- a/WebCore/html/HTMLInputElement.h
+++ b/WebCore/html/HTMLInputElement.h
@@ -281,7 +281,9 @@ private:
virtual void cacheSelection(int start, int end);
+ virtual bool isAcceptableValue(const String&) const;
virtual String sanitizeValue(const String&) const;
+ virtual bool hasUnacceptableValue() const;
virtual void documentDidBecomeActive();
diff --git a/WebCore/html/HTMLLinkElement.cpp b/WebCore/html/HTMLLinkElement.cpp
index bc7b9a6..939b375 100644
--- a/WebCore/html/HTMLLinkElement.cpp
+++ b/WebCore/html/HTMLLinkElement.cpp
@@ -27,7 +27,7 @@
#include "Attribute.h"
#include "CSSHelper.h"
#include "CachedCSSStyleSheet.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
#include "Document.h"
#include "Frame.h"
#include "FrameLoader.h"
@@ -212,7 +212,7 @@ void HTMLLinkElement::process()
#if ENABLE(LINK_PREFETCH)
if (m_relAttribute.m_isLinkPrefetch && m_url.isValid() && document()->frame())
- document()->docLoader()->requestLinkPrefetch(m_url);
+ document()->cachedResourceLoader()->requestLinkPrefetch(m_url);
#endif
bool acceptIfTypeContainsTextCSS = document()->page() && document()->page()->settings() && document()->page()->settings()->treatsAnyTextCSSLinkAsStylesheet();
@@ -243,7 +243,7 @@ void HTMLLinkElement::process()
if (!isAlternate())
document()->addPendingSheet();
- m_cachedSheet = document()->docLoader()->requestCSSStyleSheet(m_url, charset);
+ m_cachedSheet = document()->cachedResourceLoader()->requestCSSStyleSheet(m_url, charset);
if (m_cachedSheet)
m_cachedSheet->addClient(this);
diff --git a/WebCore/html/HTMLMediaElement.cpp b/WebCore/html/HTMLMediaElement.cpp
index bc7960c..827158e 100644
--- a/WebCore/html/HTMLMediaElement.cpp
+++ b/WebCore/html/HTMLMediaElement.cpp
@@ -29,14 +29,14 @@
#include "HTMLMediaElement.h"
#include "Attribute.h"
-#include "CSSHelper.h"
-#include "CSSPropertyNames.h"
-#include "CSSValueKeywords.h"
#include "Chrome.h"
#include "ChromeClient.h"
#include "ClientRect.h"
#include "ClientRectList.h"
#include "ContentType.h"
+#include "CSSHelper.h"
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
#include "Event.h"
#include "EventNames.h"
#include "ExceptionCode.h"
@@ -48,12 +48,13 @@
#include "HTMLNames.h"
#include "HTMLSourceElement.h"
#include "HTMLVideoElement.h"
-#include "MIMETypeRegistry.h"
+#include "Logging.h"
#include "MediaDocument.h"
#include "MediaError.h"
#include "MediaList.h"
#include "MediaPlayer.h"
#include "MediaQueryEvaluator.h"
+#include "MIMETypeRegistry.h"
#include "Page.h"
#include "RenderVideo.h"
#include "RenderView.h"
@@ -78,10 +79,33 @@ using namespace std;
namespace WebCore {
+#if !LOG_DISABLED
+static String urlForLogging(const String& url)
+{
+ static unsigned maximumURLLengthForLogging = 128;
+
+ if (url.length() < maximumURLLengthForLogging)
+ return url;
+ return url.substring(0, maximumURLLengthForLogging) + "...";
+}
+
+static const char *boolString(bool val)
+{
+ return val ? "true" : "false";
+}
+#endif
+
+#ifndef LOG_MEDIA_EVENTS
+// Default to not logging events because so many are generated they can overwhelm the rest of
+// the logging.
+#define LOG_MEDIA_EVENTS 0
+#endif
+
using namespace HTMLNames;
-HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* doc)
- : HTMLElement(tagName, doc)
+HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* document)
+ : HTMLElement(tagName, document)
+ , ActiveDOMObject(document, this)
, m_loadTimer(this, &HTMLMediaElement::loadTimerFired)
, m_asyncEventTimer(this, &HTMLMediaElement::asyncEventTimerFired)
, m_progressEventTimer(this, &HTMLMediaElement::progressEventTimerFired)
@@ -132,8 +156,8 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* doc)
, m_loadInitiatedByUserGesture(false)
, m_completelyLoaded(false)
{
- document()->registerForDocumentActivationCallbacks(this);
- document()->registerForMediaVolumeCallbacks(this);
+ document->registerForDocumentActivationCallbacks(this);
+ document->registerForMediaVolumeCallbacks(this);
}
HTMLMediaElement::~HTMLMediaElement()
@@ -365,6 +389,9 @@ void HTMLMediaElement::scheduleNextSourceChild()
void HTMLMediaElement::scheduleEvent(const AtomicString& eventName)
{
+#if LOG_MEDIA_EVENTS
+ LOG(Media, "HTMLMediaElement::scheduleEvent - scheduling '%s'", eventName.string().ascii().data());
+#endif
m_pendingEvents.append(Event::create(eventName, false, true));
if (!m_asyncEventTimer.isActive())
m_asyncEventTimer.startOneShot(0);
@@ -387,6 +414,9 @@ void HTMLMediaElement::asyncEventTimerFired(Timer<HTMLMediaElement>*)
m_pendingEvents.swap(pendingEvents);
unsigned count = pendingEvents.size();
for (unsigned ndx = 0; ndx < count; ++ndx) {
+#if LOG_MEDIA_EVENTS
+ LOG(Media, "HTMLMediaElement::asyncEventTimerFired - dispatching '%s'", pendingEvents[ndx]->type().string().ascii().data());
+#endif
if (pendingEvents[ndx]->type() == eventNames().canplayEvent) {
m_dispatchingCanPlayEvent = true;
dispatchEvent(pendingEvents[ndx].release(), ec);
@@ -479,11 +509,15 @@ String HTMLMediaElement::canPlayType(const String& mimeType) const
break;
}
+ LOG(Media, "HTMLMediaElement::canPlayType(%s) -> %s", mimeType.utf8().data(), canPlay.utf8().data());
+
return canPlay;
}
void HTMLMediaElement::load(bool isUserGesture, ExceptionCode& ec)
{
+ LOG(Media, "HTMLMediaElement::load(isUserGesture : %s)", boolString(isUserGesture));
+
if (m_restrictions & RequireUserGestureForLoadRestriction && !isUserGesture)
ec = INVALID_STATE_ERR;
else {
@@ -495,6 +529,8 @@ void HTMLMediaElement::load(bool isUserGesture, ExceptionCode& ec)
void HTMLMediaElement::prepareForLoad()
{
+ LOG(Media, "HTMLMediaElement::prepareForLoad");
+
// Perform the cleanup required for the resource load algorithm to run.
stopPeriodicTimers();
m_loadTimer.stop();
@@ -578,6 +614,8 @@ void HTMLMediaElement::loadInternal()
void HTMLMediaElement::selectMediaResource()
{
+ LOG(Media, "HTMLMediaElement::selectMediaResource");
+
enum Mode { attribute, children };
Mode mode = attribute;
@@ -596,6 +634,8 @@ void HTMLMediaElement::selectMediaResource()
// ... set the networkState to NETWORK_EMPTY, and abort these steps
m_networkState = NETWORK_EMPTY;
+
+ LOG(Media, "HTMLMediaElement::selectMediaResource, nothing to load");
return;
}
@@ -616,6 +656,7 @@ void HTMLMediaElement::selectMediaResource()
KURL mediaURL = getNonEmptyURLAttribute(srcAttr);
if (mediaURL.isEmpty()) {
noneSupported();
+ LOG(Media, "HTMLMediaElement::selectMediaResource, empty 'src'");
return;
}
@@ -626,6 +667,7 @@ void HTMLMediaElement::selectMediaResource()
} else
noneSupported();
+ LOG(Media, "HTMLMediaElement::selectMediaResource, 'src' not used");
return;
}
@@ -656,6 +698,8 @@ void HTMLMediaElement::loadResource(const KURL& initialURL, ContentType& content
{
ASSERT(isSafeToLoadURL(initialURL, Complain));
+ LOG(Media, "HTMLMediaElement::loadResource(%s, %s)", urlForLogging(initialURL.string()).utf8().data(), contentType.raw().utf8().data());
+
Frame* frame = document()->frame();
if (!frame)
return;
@@ -672,6 +716,8 @@ void HTMLMediaElement::loadResource(const KURL& initialURL, ContentType& content
m_currentSrc = url;
+ LOG(Media, "HTMLMediaElement::loadResource - m_currentSrc -> %s", urlForLogging(m_currentSrc).utf8().data());
+
if (m_sendProgressEvents)
startProgressEventTimer();
@@ -698,16 +744,19 @@ void HTMLMediaElement::loadResource(const KURL& initialURL, ContentType& content
bool HTMLMediaElement::isSafeToLoadURL(const KURL& url, InvalidSourceAction actionIfInvalid)
{
- if (!url.isValid())
+ if (!url.isValid()) {
+ LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%s) -> FALSE because url is invalid", urlForLogging(url.string()).utf8().data());
return false;
+ }
Frame* frame = document()->frame();
FrameLoader* loader = frame ? frame->loader() : 0;
// don't allow remote to local urls, and check with the frame loader client.
- if (!loader || !SecurityOrigin::canLoad(url, String(), document())) {
+ if (!loader || !SecurityOrigin::canDisplay(url, String(), document())) {
if (actionIfInvalid == Complain)
FrameLoader::reportLocalLoadFailed(frame, url.string());
+ LOG(Media, "HTMLMediaElement::isSafeToLoadURL(%s) -> FALSE rejected by SecurityOrigin", urlForLogging(url.string()).utf8().data());
return false;
}
@@ -727,6 +776,8 @@ void HTMLMediaElement::startProgressEventTimer()
void HTMLMediaElement::waitForSourceChange()
{
+ LOG(Media, "HTMLMediaElement::waitForSourceChange");
+
stopPeriodicTimers();
m_loadState = WaitingForSource;
@@ -739,6 +790,8 @@ void HTMLMediaElement::waitForSourceChange()
void HTMLMediaElement::noneSupported()
{
+ LOG(Media, "HTMLMediaElement::noneSupported");
+
stopPeriodicTimers();
m_loadState = WaitingForSource;
m_currentSourceNode = 0;
@@ -769,6 +822,8 @@ void HTMLMediaElement::noneSupported()
void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err)
{
+ LOG(Media, "HTMLMediaElement::mediaEngineError(%d)", static_cast<int>(err->code()));
+
// 1 - The user agent should cancel the fetching process.
stopPeriodicTimers();
m_loadState = WaitingForSource;
@@ -794,6 +849,8 @@ void HTMLMediaElement::mediaEngineError(PassRefPtr<MediaError> err)
void HTMLMediaElement::cancelPendingEventsAndCallbacks()
{
+ LOG(Media, "HTMLMediaElement::cancelPendingEventsAndCallbacks");
+
m_pendingEvents.clear();
for (Node* node = firstChild(); node; node = node->nextSibling()) {
@@ -821,6 +878,8 @@ void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*)
void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
{
+ LOG(Media, "HTMLMediaElement::setNetworkState(%d) - current state is %d", static_cast<int>(state), static_cast<int>(m_networkState));
+
if (state == MediaPlayer::Empty) {
// just update the cached state and leave, we can't do anything
m_networkState = NETWORK_EMPTY;
@@ -834,10 +893,13 @@ void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state)
// <source> children, schedule the next one
if (m_readyState < HAVE_METADATA && m_loadState == LoadingFromSourceElement) {
m_currentSourceNode->scheduleErrorEvent();
- if (havePotentialSourceChild())
+ if (havePotentialSourceChild()) {
+ LOG(Media, "HTMLMediaElement::setNetworkState scheduling next <source>");
scheduleNextSourceChild();
- else
+ } else {
+ LOG(Media, "HTMLMediaElement::setNetworkState no more <source> elements, waiting");
waitForSourceChange();
+ }
return;
}
@@ -891,6 +953,8 @@ void HTMLMediaElement::mediaPlayerReadyStateChanged(MediaPlayer*)
void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state)
{
+ LOG(Media, "HTMLMediaElement::setReadyState(%d) - current state is %d,", static_cast<int>(state), static_cast<int>(m_readyState));
+
// Set "wasPotentiallyPlaying" BEFORE updating m_readyState, potentiallyPlaying() uses it
bool wasPotentiallyPlaying = potentiallyPlaying();
@@ -1004,18 +1068,22 @@ void HTMLMediaElement::progressEventTimerFired(Timer<HTMLMediaElement>*)
void HTMLMediaElement::rewind(float timeDelta)
{
+ LOG(Media, "HTMLMediaElement::rewind(%f)", timeDelta);
+
ExceptionCode e;
setCurrentTime(max(currentTime() - timeDelta, minTimeSeekable()), e);
}
void HTMLMediaElement::returnToRealtime()
{
+ LOG(Media, "HTMLMediaElement::returnToRealtime");
ExceptionCode e;
setCurrentTime(maxTimeSeekable(), e);
}
void HTMLMediaElement::addPlayedRange(float start, float end)
{
+ LOG(Media, "HTMLMediaElement::addPlayedRange(%f, %f)", start, end);
if (!m_playedTimeRanges)
m_playedTimeRanges = TimeRanges::create();
m_playedTimeRanges->add(start, end);
@@ -1028,6 +1096,8 @@ bool HTMLMediaElement::supportsSave() const
void HTMLMediaElement::seek(float time, ExceptionCode& ec)
{
+ LOG(Media, "HTMLMediaElement::seek(%f)", time);
+
// 4.8.9.9 Seeking
// 1 - If the media element's readyState is HAVE_NOTHING, then raise an INVALID_STATE_ERR exception.
@@ -1080,6 +1150,8 @@ void HTMLMediaElement::seek(float time, ExceptionCode& ec)
void HTMLMediaElement::finishSeek()
{
+ LOG(Media, "HTMLMediaElement::finishSeek");
+
// 4.8.10.10 Seeking step 12
m_seeking = false;
@@ -1164,6 +1236,8 @@ float HTMLMediaElement::playbackRate() const
void HTMLMediaElement::setPlaybackRate(float rate)
{
+ LOG(Media, "HTMLMediaElement::setPlaybackRate(%f)", rate);
+
if (m_playbackRate != rate) {
m_playbackRate = rate;
scheduleEvent(eventNames().ratechangeEvent);
@@ -1179,6 +1253,8 @@ bool HTMLMediaElement::webkitPreservesPitch() const
void HTMLMediaElement::setWebkitPreservesPitch(bool preservesPitch)
{
+ LOG(Media, "HTMLMediaElement::setWebkitPreservesPitch(%s)", boolString(preservesPitch));
+
m_webkitPreservesPitch = preservesPitch;
if (!m_player)
@@ -1202,6 +1278,7 @@ bool HTMLMediaElement::autoplay() const
void HTMLMediaElement::setAutoplay(bool b)
{
+ LOG(Media, "HTMLMediaElement::setAutoplay(%s)", boolString(b));
setBooleanAttribute(autoplayAttr, b);
}
@@ -1225,11 +1302,14 @@ String HTMLMediaElement::preload() const
void HTMLMediaElement::setPreload(const String& preload)
{
+ LOG(Media, "HTMLMediaElement::setPreload(%s)", preload.utf8().data());
setAttribute(preloadAttr, preload);
}
void HTMLMediaElement::play(bool isUserGesture)
{
+ LOG(Media, "HTMLMediaElement::play(isUserGesture : %s)", boolString(isUserGesture));
+
if (m_restrictions & RequireUserGestureForRateChangeRestriction && !isUserGesture)
return;
@@ -1249,6 +1329,8 @@ void HTMLMediaElement::play(bool isUserGesture)
void HTMLMediaElement::playInternal()
{
+ LOG(Media, "HTMLMediaElement::playInternal");
+
// 4.8.10.9. Playing the media resource
if (!m_player || m_networkState == NETWORK_EMPTY)
scheduleLoad();
@@ -1276,6 +1358,8 @@ void HTMLMediaElement::playInternal()
void HTMLMediaElement::pause(bool isUserGesture)
{
+ LOG(Media, "HTMLMediaElement::pause(isUserGesture : %s)", boolString(isUserGesture));
+
if (m_restrictions & RequireUserGestureForRateChangeRestriction && !isUserGesture)
return;
@@ -1285,6 +1369,8 @@ void HTMLMediaElement::pause(bool isUserGesture)
void HTMLMediaElement::pauseInternal()
{
+ LOG(Media, "HTMLMediaElement::pauseInternal");
+
// 4.8.10.9. Playing the media resource
if (!m_player || m_networkState == NETWORK_EMPTY)
scheduleLoad();
@@ -1307,6 +1393,7 @@ bool HTMLMediaElement::loop() const
void HTMLMediaElement::setLoop(bool b)
{
+ LOG(Media, "HTMLMediaElement::setLoop(%s)", boolString(b));
setBooleanAttribute(loopAttr, b);
}
@@ -1323,6 +1410,7 @@ bool HTMLMediaElement::controls() const
void HTMLMediaElement::setControls(bool b)
{
+ LOG(Media, "HTMLMediaElement::setControls(%s)", boolString(b));
setBooleanAttribute(controlsAttr, b);
}
@@ -1333,6 +1421,8 @@ float HTMLMediaElement::volume() const
void HTMLMediaElement::setVolume(float vol, ExceptionCode& ec)
{
+ LOG(Media, "HTMLMediaElement::setControls(%f)", vol);
+
if (vol < 0.0f || vol > 1.0f) {
ec = INDEX_SIZE_ERR;
return;
@@ -1352,6 +1442,8 @@ bool HTMLMediaElement::muted() const
void HTMLMediaElement::setMuted(bool muted)
{
+ LOG(Media, "HTMLMediaElement::setMuted(%s)", boolString(muted));
+
if (m_muted != muted) {
m_muted = muted;
// Avoid recursion when the player reports volume changes.
@@ -1369,6 +1461,8 @@ void HTMLMediaElement::setMuted(bool muted)
void HTMLMediaElement::togglePlayState()
{
+ LOG(Media, "HTMLMediaElement::togglePlayState - canPlay() is %s", boolString(canPlay()));
+
// We can safely call the internal play/pause methods, which don't check restrictions, because
// this method is only called from the built-in media controller
if (canPlay())
@@ -1379,6 +1473,8 @@ void HTMLMediaElement::togglePlayState()
void HTMLMediaElement::beginScrubbing()
{
+ LOG(Media, "HTMLMediaElement::beginScrubbing - paused() is %s", boolString(paused()));
+
if (!paused()) {
if (ended()) {
// Because a media element stays in non-paused state when it reaches end, playback resumes
@@ -1396,6 +1492,8 @@ void HTMLMediaElement::beginScrubbing()
void HTMLMediaElement::endScrubbing()
{
+ LOG(Media, "HTMLMediaElement::beginScrubbing - m_pausedInternal is %s", boolString(m_pausedInternal));
+
if (m_pausedInternal)
setPausedInternal(false);
}
@@ -1482,6 +1580,13 @@ bool HTMLMediaElement::havePotentialSourceChild()
KURL HTMLMediaElement::selectNextSourceChild(ContentType *contentType, InvalidSourceAction actionIfInvalid)
{
+#if !LOG_DISABLED
+ // Don't log if this was just called to find out if there are any valid <source> elements.
+ bool shouldLog = actionIfInvalid != DoNothing;
+ if (shouldLog)
+ LOG(Media, "HTMLMediaElement::selectNextSourceChild(contentType : \"%s\")", contentType ? contentType->raw().utf8().data() : "");
+#endif
+
KURL mediaURL;
Node* node;
bool lookingForPreviousNode = m_currentSourceNode;
@@ -1501,17 +1606,29 @@ KURL HTMLMediaElement::selectNextSourceChild(ContentType *contentType, InvalidSo
// If candidate does not have a src attribute, or if its src attribute's value is the empty string ... jump down to the failed step below
mediaURL = source->getNonEmptyURLAttribute(srcAttr);
+#if !LOG_DISABLED
+ if (shouldLog)
+ LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'src' is %s", urlForLogging(mediaURL).utf8().data());
+#endif
if (mediaURL.isEmpty())
goto check_again;
if (source->hasAttribute(mediaAttr)) {
MediaQueryEvaluator screenEval("screen", document()->frame(), renderer() ? renderer()->style() : 0);
RefPtr<MediaList> media = MediaList::createAllowingDescriptionSyntax(source->media());
+#if !LOG_DISABLED
+ if (shouldLog)
+ LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'media' is %s", source->media().utf8().data());
+#endif
if (!screenEval.eval(media.get()))
goto check_again;
}
if (source->hasAttribute(typeAttr)) {
+#if !LOG_DISABLED
+ if (shouldLog)
+ LOG(Media, "HTMLMediaElement::selectNextSourceChild - 'type' is %s", source->type().utf8().data());
+#endif
if (!MediaPlayer::supportsType(ContentType(source->type())))
goto check_again;
}
@@ -1533,11 +1650,17 @@ check_again:
if (!canUse)
m_currentSourceNode = 0;
+#if !LOG_DISABLED
+ if (shouldLog)
+ LOG(Media, "HTMLMediaElement::selectNextSourceChild -> %s", canUse ? urlForLogging(mediaURL.string()).utf8().data() : "");
+#endif
return canUse ? mediaURL : KURL();
}
void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
{
+ LOG(Media, "HTMLMediaElement::mediaPlayerTimeChanged");
+
beginProcessingMediaPlayerCallback();
// Always call scheduleTimeupdateEvent when the media engine reports a time discontinuity,
@@ -1572,6 +1695,8 @@ void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*)
void HTMLMediaElement::mediaPlayerVolumeChanged(MediaPlayer*)
{
+ LOG(Media, "HTMLMediaElement::mediaPlayerVolumeChanged");
+
beginProcessingMediaPlayerCallback();
if (m_player)
m_volume = m_player->volume();
@@ -1581,6 +1706,8 @@ void HTMLMediaElement::mediaPlayerVolumeChanged(MediaPlayer*)
void HTMLMediaElement::mediaPlayerMuteChanged(MediaPlayer*)
{
+ LOG(Media, "HTMLMediaElement::mediaPlayerMuteChanged");
+
beginProcessingMediaPlayerCallback();
if (m_player)
setMuted(m_player->muted());
@@ -1589,6 +1716,8 @@ void HTMLMediaElement::mediaPlayerMuteChanged(MediaPlayer*)
void HTMLMediaElement::mediaPlayerDurationChanged(MediaPlayer*)
{
+ LOG(Media, "HTMLMediaElement::mediaPlayerDurationChanged");
+
beginProcessingMediaPlayerCallback();
scheduleEvent(eventNames().durationchangeEvent);
if (renderer())
@@ -1598,6 +1727,8 @@ void HTMLMediaElement::mediaPlayerDurationChanged(MediaPlayer*)
void HTMLMediaElement::mediaPlayerRateChanged(MediaPlayer*)
{
+ LOG(Media, "HTMLMediaElement::mediaPlayerRateChanged");
+
beginProcessingMediaPlayerCallback();
// Stash the rate in case the one we tried to set isn't what the engine is
// using (eg. it can't handle the rate we set)
@@ -1605,8 +1736,25 @@ void HTMLMediaElement::mediaPlayerRateChanged(MediaPlayer*)
endProcessingMediaPlayerCallback();
}
+void HTMLMediaElement::mediaPlayerPlaybackStateChanged(MediaPlayer*)
+{
+ LOG(Media, "HTMLMediaElement::mediaPlayerPlaybackStateChanged");
+
+ if (!m_player)
+ return;
+
+ beginProcessingMediaPlayerCallback();
+ if (m_player->paused())
+ pauseInternal();
+ else
+ playInternal();
+ endProcessingMediaPlayerCallback();
+}
+
void HTMLMediaElement::mediaPlayerSawUnsupportedTracks(MediaPlayer*)
{
+ LOG(Media, "HTMLMediaElement::mediaPlayerSawUnsupportedTracks");
+
// The MediaPlayer came across content it cannot completely handle.
// This is normally acceptable except when we are in a standalone
// MediaDocument. If so, tell the document what has happened.
@@ -1628,6 +1776,8 @@ void HTMLMediaElement::mediaPlayerRepaint(MediaPlayer*)
void HTMLMediaElement::mediaPlayerSizeChanged(MediaPlayer*)
{
+ LOG(Media, "HTMLMediaElement::mediaPlayerSizeChanged");
+
beginProcessingMediaPlayerCallback();
if (renderer())
renderer()->updateFromElement();
@@ -1646,6 +1796,8 @@ bool HTMLMediaElement::mediaPlayerRenderingCanBeAccelerated(MediaPlayer*)
void HTMLMediaElement::mediaPlayerRenderingModeChanged(MediaPlayer*)
{
+ LOG(Media, "HTMLMediaElement::mediaPlayerRenderingModeChanged");
+
// Kick off a fake recalcStyle that will update the compositing tree.
setNeedsStyleRecalc(SyntheticStyleChange);
}
@@ -1780,24 +1932,36 @@ void HTMLMediaElement::updatePlayState()
bool shouldBePlaying = potentiallyPlaying();
bool playerPaused = m_player->paused();
- if (shouldBePlaying && playerPaused) {
+
+ LOG(Media, "HTMLMediaElement::updatePlayState - shouldBePlaying = %s, playerPaused = %s",
+ boolString(shouldBePlaying), boolString(playerPaused));
+
+ if (shouldBePlaying) {
setDisplayMode(Video);
- // Set rate before calling play in case the rate was set before the media engine wasn't setup.
- // The media engine should just stash the rate since it isn't already playing.
- m_player->setRate(m_playbackRate);
- m_player->play();
+ if (playerPaused) {
+ // Set rate before calling play in case the rate was set before the media engine was setup.
+ // The media engine should just stash the rate since it isn't already playing.
+ m_player->setRate(m_playbackRate);
+ m_player->play();
+ }
+
startPlaybackProgressTimer();
m_playing = true;
- } else if (!shouldBePlaying && !playerPaused) {
- m_player->pause();
+
+ } else { // Should not be playing right now
+ if (!playerPaused)
+ m_player->pause();
+
m_playbackProgressTimer.stop();
m_playing = false;
float time = currentTime();
if (time > m_lastSeekTime)
addPlayedRange(m_lastSeekTime, time);
- } else if (couldPlayIfEnoughData() && playerPaused)
- m_player->prepareToPlay();
+
+ if (couldPlayIfEnoughData())
+ m_player->prepareToPlay();
+ }
if (renderer())
renderer()->updateFromElement();
@@ -1817,6 +1981,8 @@ void HTMLMediaElement::stopPeriodicTimers()
void HTMLMediaElement::userCancelledLoad()
{
+ LOG(Media, "HTMLMediaElement::userCancelledLoad");
+
if (m_networkState == NETWORK_EMPTY || m_completelyLoaded)
return;
@@ -1855,8 +2021,21 @@ void HTMLMediaElement::userCancelledLoad()
m_readyState = HAVE_NOTHING;
}
-void HTMLMediaElement::documentWillBecomeInactive()
+bool HTMLMediaElement::canSuspend() const
+{
+ return true;
+}
+
+void HTMLMediaElement::stop()
+{
+ LOG(Media, "HTMLMediaElement::stop");
+ suspend();
+}
+
+void HTMLMediaElement::suspend()
{
+ LOG(Media, "HTMLMediaElement::suspend");
+
if (m_isFullscreen)
exitFullscreen();
@@ -1873,8 +2052,10 @@ void HTMLMediaElement::documentWillBecomeInactive()
cancelPendingEventsAndCallbacks();
}
-void HTMLMediaElement::documentDidBecomeActive()
+void HTMLMediaElement::resume()
{
+ LOG(Media, "HTMLMediaElement::resume");
+
m_inActiveDocument = true;
setPausedInternal(false);
@@ -1891,8 +2072,18 @@ void HTMLMediaElement::documentDidBecomeActive()
renderer()->updateFromElement();
}
+bool HTMLMediaElement::hasPendingActivity() const
+{
+ // Return true when we have pending events so we can't fire events after the JS
+ // object gets collected.
+ bool pending = m_pendingEvents.size();
+ LOG(Media, "HTMLMediaElement::hasPendingActivity -> %s", boolString(pending));
+ return pending;
+}
+
void HTMLMediaElement::mediaVolumeDidChange()
{
+ LOG(Media, "HTMLMediaElement::mediaVolumeDidChange");
updateVolume();
}
@@ -2004,6 +2195,8 @@ void HTMLMediaElement::createMediaPlayerProxy()
if (!loader)
return;
+ LOG(Media, "HTMLMediaElement::createMediaPlayerProxy");
+
KURL url;
Vector<String> paramNames;
Vector<String> paramValues;
@@ -2016,10 +2209,26 @@ void HTMLMediaElement::createMediaPlayerProxy()
if (m_proxyWidget)
m_needWidgetUpdate = false;
}
+
+void HTMLMediaElement::updateWidget(bool)
+{
+ mediaElement->setNeedWidgetUpdate(false);
+
+ Vector<String> paramNames;
+ Vector<String> paramValues;
+ KURL kurl;
+
+ mediaElement->getPluginProxyParams(kurl, paramNames, paramValues);
+ SubframeLoader* loader = document()->frame()->loader()->subframeLoader();
+ loader->loadMediaPlayerProxyPlugin(mediaElement, kurl, paramNames, paramValues);
+}
+
#endif // ENABLE(PLUGIN_PROXY_FOR_VIDEO)
void HTMLMediaElement::enterFullscreen()
{
+ LOG(Media, "HTMLMediaElement::enterFullscreen");
+
ASSERT(!m_isFullscreen);
m_isFullscreen = true;
if (document() && document()->page()) {
@@ -2030,6 +2239,8 @@ void HTMLMediaElement::enterFullscreen()
void HTMLMediaElement::exitFullscreen()
{
+ LOG(Media, "HTMLMediaElement::exitFullscreen");
+
ASSERT(m_isFullscreen);
m_isFullscreen = false;
if (document() && document()->page()) {
@@ -2062,6 +2273,8 @@ bool HTMLMediaElement::closedCaptionsVisible() const
void HTMLMediaElement::setClosedCaptionsVisible(bool closedCaptionVisible)
{
+ LOG(Media, "HTMLMediaElement::setClosedCaptionsVisible(%s)", boolString(closedCaptionVisible));
+
if (!m_player ||!hasClosedCaptions())
return;
@@ -2089,6 +2302,8 @@ bool HTMLMediaElement::webkitHasClosedCaptions() const
void HTMLMediaElement::mediaCanStart()
{
+ LOG(Media, "HTMLMediaElement::mediaCanStart");
+
ASSERT(m_isWaitingUntilMediaCanStart);
m_isWaitingUntilMediaCanStart = false;
loadInternal();
@@ -2118,6 +2333,8 @@ void HTMLMediaElement::setShouldDelayLoadEvent(bool shouldDelay)
return;
}
+ LOG(Media, "HTMLMediaElement::setShouldDelayLoadEvent(%s)", boolString(shouldDelay));
+
m_shouldDelayLoadEvent = shouldDelay;
m_isWaitingToDecrementLoadEventDelayCount = false;
if (shouldDelay)
diff --git a/WebCore/html/HTMLMediaElement.h b/WebCore/html/HTMLMediaElement.h
index 3895fe3..adea0fd 100644
--- a/WebCore/html/HTMLMediaElement.h
+++ b/WebCore/html/HTMLMediaElement.h
@@ -29,6 +29,7 @@
#if ENABLE(VIDEO)
#include "HTMLElement.h"
+#include "ActiveDOMObject.h"
#include "MediaCanStartListener.h"
#include "MediaPlayer.h"
@@ -51,7 +52,7 @@ class Widget;
// But it can't be until the Chromium WebMediaPlayerClientImpl class is fixed so it
// no longer depends on typecasting a MediaPlayerClient to an HTMLMediaElement.
-class HTMLMediaElement : public HTMLElement, public MediaPlayerClient, private MediaCanStartListener {
+class HTMLMediaElement : public HTMLElement, public MediaPlayerClient, private MediaCanStartListener, private ActiveDOMObject {
public:
MediaPlayer* player() const { return m_player.get(); }
@@ -153,6 +154,7 @@ public:
void getPluginProxyParams(KURL& url, Vector<String>& names, Vector<String>& values);
virtual void finishParsingChildren();
void createMediaPlayerProxy();
+ void updateWidget(bool onlyCreateNonNetscapePlugins);
#endif
bool hasSingleSecurityOrigin() const { return !m_player || m_player->hasSingleSecurityOrigin(); }
@@ -195,8 +197,13 @@ private:
float getTimeOffsetAttribute(const QualifiedName&, float valueOnError) const;
void setTimeOffsetAttribute(const QualifiedName&, float value);
- virtual void documentWillBecomeInactive();
- virtual void documentDidBecomeActive();
+ // ActiveDOMObject functions.
+ virtual bool canSuspend() const;
+ virtual void suspend();
+ virtual void resume();
+ virtual void stop();
+ virtual bool hasPendingActivity() const;
+
virtual void mediaVolumeDidChange();
virtual void updateDisplayState() { }
@@ -212,6 +219,7 @@ private:
virtual void mediaPlayerMuteChanged(MediaPlayer*);
virtual void mediaPlayerDurationChanged(MediaPlayer*);
virtual void mediaPlayerRateChanged(MediaPlayer*);
+ virtual void mediaPlayerPlaybackStateChanged(MediaPlayer*);
virtual void mediaPlayerSawUnsupportedTracks(MediaPlayer*);
virtual void mediaPlayerRepaint(MediaPlayer*);
virtual void mediaPlayerSizeChanged(MediaPlayer*);
diff --git a/WebCore/html/HTMLObjectElement.cpp b/WebCore/html/HTMLObjectElement.cpp
index e8884ef..56a6095 100644
--- a/WebCore/html/HTMLObjectElement.cpp
+++ b/WebCore/html/HTMLObjectElement.cpp
@@ -33,6 +33,7 @@
#include "HTMLFormElement.h"
#include "HTMLImageLoader.h"
#include "HTMLNames.h"
+#include "HTMLParamElement.h"
#include "MIMETypeRegistry.h"
#include "RenderEmbeddedObject.h"
#include "RenderImage.h"
@@ -115,6 +116,173 @@ void HTMLObjectElement::parseMappedAttribute(Attribute* attr)
HTMLPlugInImageElement::parseMappedAttribute(attr);
}
+typedef HashMap<String, String, CaseFoldingHash> ClassIdToTypeMap;
+
+static ClassIdToTypeMap* createClassIdToTypeMap()
+{
+ ClassIdToTypeMap* map = new ClassIdToTypeMap;
+ map->add("clsid:D27CDB6E-AE6D-11CF-96B8-444553540000", "application/x-shockwave-flash");
+ map->add("clsid:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA", "audio/x-pn-realaudio-plugin");
+ map->add("clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B", "video/quicktime");
+ map->add("clsid:166B1BCA-3F9C-11CF-8075-444553540000", "application/x-director");
+ map->add("clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6", "application/x-mplayer2");
+ map->add("clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95", "application/x-mplayer2");
+ return map;
+}
+
+static String serviceTypeForClassId(const String& classId)
+{
+ // Return early if classId is empty (since we won't do anything below).
+ // Furthermore, if classId is null, calling get() below will crash.
+ if (classId.isEmpty())
+ return String();
+
+ static ClassIdToTypeMap* map = createClassIdToTypeMap();
+ return map->get(classId);
+}
+
+static void mapDataParamToSrc(Vector<String>* paramNames, Vector<String>* paramValues)
+{
+ // Some plugins don't understand the "data" attribute of the OBJECT tag (i.e. Real and WMP
+ // require "src" attribute).
+ int srcIndex = -1, dataIndex = -1;
+ for (unsigned int i = 0; i < paramNames->size(); ++i) {
+ if (equalIgnoringCase((*paramNames)[i], "src"))
+ srcIndex = i;
+ else if (equalIgnoringCase((*paramNames)[i], "data"))
+ dataIndex = i;
+ }
+
+ if (srcIndex == -1 && dataIndex != -1) {
+ paramNames->append("src");
+ paramValues->append((*paramValues)[dataIndex]);
+ }
+}
+
+// FIXME: This function should not deal with url or serviceType!
+void HTMLObjectElement::parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues, String& url, String& serviceType)
+{
+ HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames;
+
+ // Scan the PARAM children and store their name/value pairs.
+ // Get the URL and type from the params if we don't already have them.
+ for (Node* child = firstChild(); child; child = child->nextSibling()) {
+ if (!child->hasTagName(paramTag))
+ continue;
+
+ HTMLParamElement* p = static_cast<HTMLParamElement*>(child);
+ String name = p->name();
+ if (name.isEmpty())
+ continue;
+
+ uniqueParamNames.add(name.impl());
+ paramNames.append(p->name());
+ paramValues.append(p->value());
+
+ // FIXME: url adjustment does not belong in this function.
+ if (url.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url")))
+ url = deprecatedParseURL(p->value());
+ // FIXME: serviceType calculation does not belong in this function.
+ if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) {
+ serviceType = p->value();
+ size_t pos = serviceType.find(";");
+ if (pos != notFound)
+ serviceType = serviceType.left(pos);
+ }
+ }
+
+ // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag
+ // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is
+ // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means
+ // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM,
+ // else our Java plugin will misinterpret it. [4004531]
+ String codebase;
+ if (MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) {
+ codebase = "codebase";
+ uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already
+ }
+
+ // Turn the attributes of the <object> element into arrays, but don't override <param> values.
+ NamedNodeMap* attributes = this->attributes(true);
+ if (attributes) {
+ for (unsigned i = 0; i < attributes->length(); ++i) {
+ Attribute* it = attributes->attributeItem(i);
+ const AtomicString& name = it->name().localName();
+ if (!uniqueParamNames.contains(name.impl())) {
+ paramNames.append(name.string());
+ paramValues.append(it->value().string());
+ }
+ }
+ }
+
+ mapDataParamToSrc(&paramNames, &paramValues);
+
+ // If we still don't have a type, try to map from a specific CLASSID to a type.
+ if (serviceType.isEmpty())
+ serviceType = serviceTypeForClassId(classId());
+}
+
+
+bool HTMLObjectElement::hasFallbackContent() const
+{
+ for (Node* child = firstChild(); child; child = child->nextSibling()) {
+ // Ignore whitespace-only text, and <param> tags, any other content is fallback content.
+ if (child->isTextNode()) {
+ if (!static_cast<Text*>(child)->containsOnlyWhitespace())
+ return true;
+ } else if (!child->hasTagName(paramTag))
+ return true;
+ }
+ return false;
+}
+
+// FIXME: This should be unified with HTMLEmbedElement::updateWidget and
+// moved down into HTMLPluginImageElement.cpp
+void HTMLObjectElement::updateWidget(bool onlyCreateNonNetscapePlugins)
+{
+ ASSERT(!renderEmbeddedObject()->pluginCrashedOrWasMissing());
+ // FIXME: We should ASSERT(needsWidgetUpdate()), but currently
+ // FrameView::updateWidget() calls updateWidget(false) without checking if
+ // the widget actually needs updating!
+ setNeedsWidgetUpdate(false);
+ // FIXME: This should ASSERT isFinishedParsingChildren() instead.
+ if (!isFinishedParsingChildren())
+ return;
+
+ String url = this->url();
+ String serviceType = this->serviceType();
+
+ // FIXME: These should be joined into a PluginParameters class.
+ Vector<String> paramNames;
+ Vector<String> paramValues;
+ parametersForPlugin(paramNames, paramValues, url, serviceType);
+
+ // Note: url is modified above by parametersForPlugin.
+ if (!allowedToLoadFrameURL(url))
+ return;
+
+ bool fallbackContent = hasFallbackContent();
+ renderEmbeddedObject()->setHasFallbackContent(fallbackContent);
+
+ if (onlyCreateNonNetscapePlugins && wouldLoadAsNetscapePlugin(url, serviceType))
+ return;
+
+ bool beforeLoadAllowedLoad = dispatchBeforeLoadEvent(url);
+
+ // beforeload events can modify the DOM, potentially causing
+ // RenderWidget::destroy() to be called. Ensure we haven't been
+ // destroyed before continuing.
+ // FIXME: Should this render fallback content?
+ if (!renderer())
+ return;
+
+ SubframeLoader* loader = document()->frame()->loader()->subframeLoader();
+ bool success = beforeLoadAllowedLoad && loader->requestObject(this, url, getAttribute(nameAttr), serviceType, paramNames, paramValues);
+
+ if (!success && fallbackContent)
+ renderFallbackContent();
+}
+
bool HTMLObjectElement::rendererIsNeeded(RenderStyle* style)
{
// FIXME: This check should not be needed, detached documents never render!
diff --git a/WebCore/html/HTMLObjectElement.h b/WebCore/html/HTMLObjectElement.h
index 9fafae9..2d416c3 100644
--- a/WebCore/html/HTMLObjectElement.h
+++ b/WebCore/html/HTMLObjectElement.h
@@ -31,8 +31,6 @@ class HTMLObjectElement : public HTMLPlugInImageElement {
public:
static PassRefPtr<HTMLObjectElement> create(const QualifiedName&, Document*, bool createdByParser);
- void renderFallbackContent();
-
bool isDocNamedItem() const { return m_docNamedItem; }
const String& classId() const { return m_classId; }
@@ -40,6 +38,7 @@ public:
bool containsJavaApplet() const;
virtual bool useFallbackContent() const { return m_useFallbackContent; }
+ void renderFallbackContent();
private:
HTMLObjectElement(const QualifiedName&, Document*, bool createdByParser);
@@ -59,8 +58,15 @@ private:
virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const;
+ virtual void updateWidget(bool onlyCreateNonNetscapePlugins);
void updateDocNamedItem();
+ bool hasFallbackContent() const;
+
+ // FIXME: This function should not deal with url or serviceType
+ // so that we can better share code between <object> and <embed>.
+ void parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues, String& url, String& serviceType);
+
AtomicString m_id;
String m_classId;
bool m_docNamedItem : 1;
diff --git a/WebCore/html/HTMLPlugInImageElement.cpp b/WebCore/html/HTMLPlugInImageElement.cpp
index 75407dd..9ac5ad8 100644
--- a/WebCore/html/HTMLPlugInImageElement.cpp
+++ b/WebCore/html/HTMLPlugInImageElement.cpp
@@ -26,6 +26,7 @@
#include "FrameLoaderClient.h"
#include "HTMLImageLoader.h"
#include "Image.h"
+#include "Page.h"
#include "RenderEmbeddedObject.h"
#include "RenderImage.h"
@@ -63,6 +64,46 @@ bool HTMLPlugInImageElement::isImageType()
return Image::supportsType(m_serviceType);
}
+// We don't use m_url, as it may not be the final URL that the object loads,
+// depending on <param> values.
+bool HTMLPlugInImageElement::allowedToLoadFrameURL(const String& url)
+{
+ ASSERT(document());
+ ASSERT(document()->frame());
+ if (document()->frame()->page()->frameCount() >= Page::maxNumberOfFrames)
+ return false;
+
+ // We allow one level of self-reference because some sites depend on that.
+ // But we don't allow more than one.
+ KURL completeURL = document()->completeURL(url);
+ bool foundSelfReference = false;
+ for (Frame* frame = document()->frame(); frame; frame = frame->tree()->parent()) {
+ if (equalIgnoringFragmentIdentifier(frame->loader()->url(), completeURL)) {
+ if (foundSelfReference)
+ return false;
+ foundSelfReference = true;
+ }
+ }
+ return true;
+}
+
+// We don't use m_url, or m_serviceType as they may not be the final values
+// that <object> uses depending on <param> values.
+bool HTMLPlugInImageElement::wouldLoadAsNetscapePlugin(const String& url, const String& serviceType)
+{
+ ASSERT(document());
+ ASSERT(document()->frame());
+ FrameLoader* frameLoader = document()->frame()->loader();
+ ASSERT(frameLoader);
+ KURL completedURL;
+ if (!url.isEmpty())
+ completedURL = frameLoader->completeURL(url);
+
+ if (frameLoader->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin)
+ return true;
+ return false;
+}
+
RenderObject* HTMLPlugInImageElement::createRenderer(RenderArena* arena, RenderStyle* style)
{
// Fallback content breaks the DOM->Renderer class relationship of this
@@ -106,7 +147,7 @@ void HTMLPlugInImageElement::attach()
void HTMLPlugInImageElement::detach()
{
- // FIXME: Because of the insanity that is HTMLObjectElement::recalcStyle,
+ // FIXME: Because of the insanity that is HTMLPlugInImageElement::recalcStyle,
// we can end up detaching during an attach() call, before we even have a
// renderer. In that case, don't mark the widget for update.
if (attached() && renderer() && !useFallbackContent())
@@ -115,11 +156,18 @@ void HTMLPlugInImageElement::detach()
HTMLPlugInElement::detach();
}
-void HTMLPlugInImageElement::updateWidget()
+void HTMLPlugInImageElement::updateWidgetIfNecessary()
{
document()->updateStyleIfNeeded();
- if (needsWidgetUpdate() && renderEmbeddedObject() && !useFallbackContent() && !isImageType())
- renderEmbeddedObject()->updateWidget(true);
+
+ if (!needsWidgetUpdate() || useFallbackContent() || isImageType())
+ return;
+
+ if (!renderEmbeddedObject() || renderEmbeddedObject()->pluginCrashedOrWasMissing())
+ return;
+
+ // True indicates that this code path should only create non-netscape plugins (no clue why).
+ updateWidget(true);
}
void HTMLPlugInImageElement::finishParsingChildren()
@@ -142,7 +190,7 @@ void HTMLPlugInImageElement::willMoveToNewOwnerDocument()
void HTMLPlugInImageElement::updateWidgetCallback(Node* n)
{
- static_cast<HTMLPlugInImageElement*>(n)->updateWidget();
+ static_cast<HTMLPlugInImageElement*>(n)->updateWidgetIfNecessary();
}
} // namespace WebCore
diff --git a/WebCore/html/HTMLPlugInImageElement.h b/WebCore/html/HTMLPlugInImageElement.h
index 65c5f37..60ad0e6 100644
--- a/WebCore/html/HTMLPlugInImageElement.h
+++ b/WebCore/html/HTMLPlugInImageElement.h
@@ -27,23 +27,23 @@
namespace WebCore {
class HTMLImageLoader;
+class FrameLoader;
// Base class for HTMLObjectElement and HTMLEmbedElement
class HTMLPlugInImageElement : public HTMLPlugInElement {
public:
- const String& serviceType() const { return m_serviceType; }
- const String& url() const { return m_url; }
-
- bool needsWidgetUpdate() const { return m_needsWidgetUpdate; }
- void setNeedsWidgetUpdate(bool needsWidgetUpdate) { m_needsWidgetUpdate = needsWidgetUpdate; }
-
RenderEmbeddedObject* renderEmbeddedObject() const;
+ virtual void updateWidget(bool onlyCreateNonNetscapePlugins) = 0;
+
protected:
HTMLPlugInImageElement(const QualifiedName& tagName, Document*, bool createdByParser);
bool isImageType();
+ const String& serviceType() const { return m_serviceType; }
+ const String& url() const { return m_url; }
+
OwnPtr<HTMLImageLoader> m_imageLoader;
String m_serviceType;
String m_url;
@@ -52,6 +52,12 @@ protected:
virtual void attach();
virtual void detach();
+ bool needsWidgetUpdate() const { return m_needsWidgetUpdate; }
+ void setNeedsWidgetUpdate(bool needsWidgetUpdate) { m_needsWidgetUpdate = needsWidgetUpdate; }
+
+ bool allowedToLoadFrameURL(const String& url);
+ bool wouldLoadAsNetscapePlugin(const String& url, const String& serviceType);
+
private:
virtual bool canLazyAttach() { return false; }
virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
@@ -60,7 +66,7 @@ private:
virtual void finishParsingChildren();
virtual void willMoveToNewOwnerDocument();
- void updateWidget();
+ void updateWidgetIfNecessary();
virtual bool useFallbackContent() const { return false; }
bool m_needsWidgetUpdate;
diff --git a/WebCore/html/HTMLSelectElement.cpp b/WebCore/html/HTMLSelectElement.cpp
index b1b6d23..c680e92 100644
--- a/WebCore/html/HTMLSelectElement.cpp
+++ b/WebCore/html/HTMLSelectElement.cpp
@@ -85,8 +85,17 @@ void HTMLSelectElement::setSelectedIndex(int optionIndex, bool deselect)
SelectElement::setSelectedIndex(m_data, this, optionIndex, deselect, false, false);
}
-void HTMLSelectElement::setSelectedIndexByUser(int optionIndex, bool deselect, bool fireOnChangeNow)
+void HTMLSelectElement::setSelectedIndexByUser(int optionIndex, bool deselect, bool fireOnChangeNow, bool allowMultipleSelection)
{
+ // List box selects can fire onchange events through user interaction, such as
+ // mousedown events. This allows that same behavior programmatically.
+ if (!m_data.usesMenuList()) {
+ updateSelectedState(m_data, this, optionIndex, allowMultipleSelection, false);
+ if (fireOnChangeNow)
+ listBoxOnChange();
+ return;
+ }
+
// Bail out if this index is already the selected one, to avoid running unnecessary JavaScript that can mess up
// autofill, when there is no actual change (see https://bugs.webkit.org/show_bug.cgi?id=35256 and rdar://7467917 ).
// Perhaps this logic could be moved into SelectElement, but some callers of SelectElement::setSelectedIndex()
diff --git a/WebCore/html/HTMLSelectElement.h b/WebCore/html/HTMLSelectElement.h
index 79b0789..a3b4460 100644
--- a/WebCore/html/HTMLSelectElement.h
+++ b/WebCore/html/HTMLSelectElement.h
@@ -41,7 +41,7 @@ public:
virtual int selectedIndex() const;
virtual void setSelectedIndex(int index, bool deselect = true);
- virtual void setSelectedIndexByUser(int index, bool deselect = true, bool fireOnChangeNow = false);
+ virtual void setSelectedIndexByUser(int index, bool deselect = true, bool fireOnChangeNow = false, bool allowMultipleSelection = false);
unsigned length() const;
diff --git a/WebCore/html/HTMLViewSourceDocument.cpp b/WebCore/html/HTMLViewSourceDocument.cpp
index 3299b27..f7217eb 100644
--- a/WebCore/html/HTMLViewSourceDocument.cpp
+++ b/WebCore/html/HTMLViewSourceDocument.cpp
@@ -41,7 +41,7 @@
#include "HTMLViewSourceParser.h"
#include "SegmentedString.h"
#include "Text.h"
-#include "TextDocument.h"
+#include "TextViewSourceParser.h"
namespace WebCore {
@@ -58,7 +58,6 @@ HTMLViewSourceDocument::HTMLViewSourceDocument(Frame* frame, const KURL& url, co
PassRefPtr<DocumentParser> HTMLViewSourceDocument::createParser()
{
- // Use HTMLDocumentParser if applicable, otherwise use TextDocumentParser.
if (m_type == "text/html" || m_type == "application/xhtml+xml" || m_type == "image/svg+xml" || DOMImplementation::isXMLMIMEType(m_type)
#if ENABLE(XHTMLMP)
|| m_type == "application/vnd.wap.xhtml+xml"
@@ -66,7 +65,7 @@ PassRefPtr<DocumentParser> HTMLViewSourceDocument::createParser()
)
return HTMLViewSourceParser::create(this);
- return createTextDocumentParser(this);
+ return TextViewSourceParser::create(this);
}
void HTMLViewSourceDocument::createContainingTable()
@@ -96,13 +95,6 @@ void HTMLViewSourceDocument::createContainingTable()
m_current = m_tbody;
}
-void HTMLViewSourceDocument::addViewSourceText(const String& text)
-{
- if (!m_current)
- createContainingTable();
- addText(text, "");
-}
-
void HTMLViewSourceDocument::addSource(const String& source, HTMLToken& token)
{
if (!m_current)
diff --git a/WebCore/html/HTMLViewSourceDocument.h b/WebCore/html/HTMLViewSourceDocument.h
index 445c95b..30e4df3 100644
--- a/WebCore/html/HTMLViewSourceDocument.h
+++ b/WebCore/html/HTMLViewSourceDocument.h
@@ -42,9 +42,6 @@ public:
void addSource(const String&, HTMLToken&);
- void addViewSourceToken(HTMLToken&); // Used by the HTMLDocumentParser.
- void addViewSourceText(const String&); // Used by the TextDocumentParser.
-
private:
HTMLViewSourceDocument(Frame*, const KURL&, const String& mimeType);
diff --git a/WebCore/html/ImageDocument.cpp b/WebCore/html/ImageDocument.cpp
new file mode 100644
index 0000000..6951b7b
--- /dev/null
+++ b/WebCore/html/ImageDocument.cpp
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ImageDocument.h"
+
+#include "CachedImage.h"
+#include "DocumentLoader.h"
+#include "EventListener.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "FrameLoaderClient.h"
+#include "FrameView.h"
+#include "HTMLImageElement.h"
+#include "HTMLNames.h"
+#include "LocalizedStrings.h"
+#include "MouseEvent.h"
+#include "NotImplemented.h"
+#include "Page.h"
+#include "RawDataDocumentParser.h"
+#include "Settings.h"
+
+using std::min;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+class ImageEventListener : public EventListener {
+public:
+ static PassRefPtr<ImageEventListener> create(ImageDocument* document) { return adoptRef(new ImageEventListener(document)); }
+ static const ImageEventListener* cast(const EventListener* listener)
+ {
+ return listener->type() == ImageEventListenerType
+ ? static_cast<const ImageEventListener*>(listener)
+ : 0;
+ }
+
+ virtual bool operator==(const EventListener& other);
+
+private:
+ ImageEventListener(ImageDocument* document)
+ : EventListener(ImageEventListenerType)
+ , m_doc(document)
+ {
+ }
+
+ virtual void handleEvent(ScriptExecutionContext*, Event*);
+
+ ImageDocument* m_doc;
+};
+
+class ImageDocumentParser : public RawDataDocumentParser {
+public:
+ static PassRefPtr<ImageDocumentParser> create(ImageDocument* document)
+ {
+ return adoptRef(new ImageDocumentParser(document));
+ }
+
+ ImageDocument* document() const
+ {
+ return static_cast<ImageDocument*>(RawDataDocumentParser::document());
+ }
+
+private:
+ ImageDocumentParser(ImageDocument* document)
+ : RawDataDocumentParser(document)
+ {
+ }
+
+ virtual void appendBytes(DocumentWriter*, const char*, int, bool);
+ virtual void finish();
+};
+
+class ImageDocumentElement : public HTMLImageElement {
+public:
+ static PassRefPtr<ImageDocumentElement> create(ImageDocument*);
+
+private:
+ ImageDocumentElement(ImageDocument* document)
+ : HTMLImageElement(imgTag, document)
+ , m_imageDocument(document)
+ {
+ }
+
+ virtual ~ImageDocumentElement();
+ virtual void willMoveToNewOwnerDocument();
+
+ ImageDocument* m_imageDocument;
+};
+
+inline PassRefPtr<ImageDocumentElement> ImageDocumentElement::create(ImageDocument* document)
+{
+ return adoptRef(new ImageDocumentElement(document));
+}
+
+// --------
+
+static float pageZoomFactor(Document* document)
+{
+ FrameView* view = document->view();
+ return view ? view->pageZoomFactor() : 1;
+}
+
+void ImageDocumentParser::appendBytes(DocumentWriter*, const char*, int, bool)
+{
+ Frame* frame = document()->frame();
+ Settings* settings = frame->settings();
+ if (!frame->loader()->client()->allowImages(!settings || settings->areImagesEnabled()))
+ return;
+
+ CachedImage* cachedImage = document()->cachedImage();
+ cachedImage->data(frame->loader()->documentLoader()->mainResourceData(), false);
+
+ document()->imageChanged();
+}
+
+void ImageDocumentParser::finish()
+{
+ if (!isStopped() && document()->imageElement()) {
+ CachedImage* cachedImage = document()->cachedImage();
+ RefPtr<SharedBuffer> data = document()->frame()->loader()->documentLoader()->mainResourceData();
+
+ // If this is a multipart image, make a copy of the current part, since the resource data
+ // will be overwritten by the next part.
+ if (document()->frame()->loader()->documentLoader()->isLoadingMultipartContent())
+ data = data->copy();
+
+ cachedImage->data(data.release(), true);
+ cachedImage->finish();
+
+ cachedImage->setResponse(document()->frame()->loader()->documentLoader()->response());
+
+ // Report the natural image size in the page title, regardless of zoom
+ // level.
+ IntSize size = cachedImage->imageSize(1.0f);
+ if (size.width()) {
+ // Compute the title, we use the decoded filename of the resource, falling
+ // back on the (decoded) hostname if there is no path.
+ String fileName = decodeURLEscapeSequences(document()->url().lastPathComponent());
+ if (fileName.isEmpty())
+ fileName = document()->url().host();
+ document()->setTitle(imageTitle(fileName, size));
+ }
+
+ document()->imageChanged();
+ }
+
+ document()->finishedParsing();
+}
+
+// --------
+
+ImageDocument::ImageDocument(Frame* frame, const KURL& url)
+ : HTMLDocument(frame, url)
+ , m_imageElement(0)
+ , m_imageSizeIsKnown(false)
+ , m_didShrinkImage(false)
+ , m_shouldShrinkImage(shouldShrinkToFit())
+{
+ setCompatibilityMode(QuirksMode);
+ lockCompatibilityMode();
+}
+
+PassRefPtr<DocumentParser> ImageDocument::createParser()
+{
+ return ImageDocumentParser::create(this);
+}
+
+void ImageDocument::createDocumentStructure()
+{
+ ExceptionCode ec;
+
+ RefPtr<Element> rootElement = Document::createElement(htmlTag, false);
+ appendChild(rootElement, ec);
+
+ if (frame() && frame()->loader())
+ frame()->loader()->dispatchDocumentElementAvailable();
+
+ RefPtr<Element> body = Document::createElement(bodyTag, false);
+ body->setAttribute(styleAttr, "margin: 0px;");
+
+ rootElement->appendChild(body, ec);
+
+ RefPtr<ImageDocumentElement> imageElement = ImageDocumentElement::create(this);
+
+ imageElement->setAttribute(styleAttr, "-webkit-user-select: none");
+ imageElement->setLoadManually(true);
+ imageElement->setSrc(url().string());
+
+ body->appendChild(imageElement, ec);
+
+ if (shouldShrinkToFit()) {
+ // Add event listeners
+ RefPtr<EventListener> listener = ImageEventListener::create(this);
+ if (DOMWindow* domWindow = this->domWindow())
+ domWindow->addEventListener("resize", listener, false);
+ imageElement->addEventListener("click", listener.release(), false);
+ }
+
+ m_imageElement = imageElement.get();
+}
+
+float ImageDocument::scale() const
+{
+ if (!m_imageElement)
+ return 1.0f;
+
+ FrameView* view = frame()->view();
+ if (!view)
+ return 1;
+
+ IntSize imageSize = m_imageElement->cachedImage()->imageSize(view->pageZoomFactor());
+ IntSize windowSize = IntSize(view->width(), view->height());
+
+ float widthScale = (float)windowSize.width() / imageSize.width();
+ float heightScale = (float)windowSize.height() / imageSize.height();
+
+ return min(widthScale, heightScale);
+}
+
+void ImageDocument::resizeImageToFit()
+{
+ if (!m_imageElement)
+ return;
+
+ IntSize imageSize = m_imageElement->cachedImage()->imageSize(pageZoomFactor(this));
+
+ float scale = this->scale();
+ m_imageElement->setWidth(static_cast<int>(imageSize.width() * scale));
+ m_imageElement->setHeight(static_cast<int>(imageSize.height() * scale));
+
+ ExceptionCode ec;
+ m_imageElement->style()->setProperty("cursor", "-webkit-zoom-in", ec);
+}
+
+void ImageDocument::imageClicked(int x, int y)
+{
+ if (!m_imageSizeIsKnown || imageFitsInWindow())
+ return;
+
+ m_shouldShrinkImage = !m_shouldShrinkImage;
+
+ if (m_shouldShrinkImage)
+ windowSizeChanged();
+ else {
+ restoreImageSize();
+
+ updateLayout();
+
+ float scale = this->scale();
+
+ int scrollX = static_cast<int>(x / scale - (float)frame()->view()->width() / 2);
+ int scrollY = static_cast<int>(y / scale - (float)frame()->view()->height() / 2);
+
+ frame()->view()->setScrollPosition(IntPoint(scrollX, scrollY));
+ }
+}
+
+void ImageDocument::imageChanged()
+{
+ ASSERT(m_imageElement);
+
+ if (m_imageSizeIsKnown)
+ return;
+
+ if (m_imageElement->cachedImage()->imageSize(pageZoomFactor(this)).isEmpty())
+ return;
+
+ m_imageSizeIsKnown = true;
+
+ if (shouldShrinkToFit()) {
+ // Force resizing of the image
+ windowSizeChanged();
+ }
+}
+
+void ImageDocument::restoreImageSize()
+{
+ if (!m_imageElement || !m_imageSizeIsKnown)
+ return;
+
+ m_imageElement->setWidth(m_imageElement->cachedImage()->imageSize(pageZoomFactor(this)).width());
+ m_imageElement->setHeight(m_imageElement->cachedImage()->imageSize(pageZoomFactor(this)).height());
+
+ ExceptionCode ec;
+ if (imageFitsInWindow())
+ m_imageElement->style()->removeProperty("cursor", ec);
+ else
+ m_imageElement->style()->setProperty("cursor", "-webkit-zoom-out", ec);
+
+ m_didShrinkImage = false;
+}
+
+bool ImageDocument::imageFitsInWindow() const
+{
+ if (!m_imageElement)
+ return true;
+
+ FrameView* view = frame()->view();
+
+ IntSize imageSize = m_imageElement->cachedImage()->imageSize(view->pageZoomFactor());
+ IntSize windowSize = IntSize(view->width(), view->height());
+
+ return imageSize.width() <= windowSize.width() && imageSize.height() <= windowSize.height();
+}
+
+void ImageDocument::windowSizeChanged()
+{
+ if (!m_imageElement || !m_imageSizeIsKnown)
+ return;
+
+ bool fitsInWindow = imageFitsInWindow();
+
+ // If the image has been explicitly zoomed in, restore the cursor if the image fits
+ // and set it to a zoom out cursor if the image doesn't fit
+ if (!m_shouldShrinkImage) {
+ ExceptionCode ec;
+
+ if (fitsInWindow)
+ m_imageElement->style()->removeProperty("cursor", ec);
+ else
+ m_imageElement->style()->setProperty("cursor", "-webkit-zoom-out", ec);
+ return;
+ }
+
+ if (m_didShrinkImage) {
+ // If the window has been resized so that the image fits, restore the image size
+ // otherwise update the restored image size.
+ if (fitsInWindow)
+ restoreImageSize();
+ else
+ resizeImageToFit();
+ } else {
+ // If the image isn't resized but needs to be, then resize it.
+ if (!fitsInWindow) {
+ resizeImageToFit();
+ m_didShrinkImage = true;
+ }
+ }
+}
+
+CachedImage* ImageDocument::cachedImage()
+{
+ if (!m_imageElement)
+ createDocumentStructure();
+
+ return m_imageElement->cachedImage();
+}
+
+bool ImageDocument::shouldShrinkToFit() const
+{
+ return frame()->page()->settings()->shrinksStandaloneImagesToFit() &&
+ frame()->page()->mainFrame() == frame();
+}
+
+// --------
+
+void ImageEventListener::handleEvent(ScriptExecutionContext*, Event* event)
+{
+ if (event->type() == eventNames().resizeEvent)
+ m_doc->windowSizeChanged();
+ else if (event->type() == eventNames().clickEvent) {
+ MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
+ m_doc->imageClicked(mouseEvent->x(), mouseEvent->y());
+ }
+}
+
+bool ImageEventListener::operator==(const EventListener& listener)
+{
+ if (const ImageEventListener* imageEventListener = ImageEventListener::cast(&listener))
+ return m_doc == imageEventListener->m_doc;
+ return false;
+}
+
+// --------
+
+ImageDocumentElement::~ImageDocumentElement()
+{
+ if (m_imageDocument)
+ m_imageDocument->disconnectImageElement();
+}
+
+void ImageDocumentElement::willMoveToNewOwnerDocument()
+{
+ if (m_imageDocument) {
+ m_imageDocument->disconnectImageElement();
+ m_imageDocument = 0;
+ }
+ HTMLImageElement::willMoveToNewOwnerDocument();
+}
+
+}
diff --git a/WebCore/html/ImageDocument.h b/WebCore/html/ImageDocument.h
new file mode 100644
index 0000000..5d00bd6
--- /dev/null
+++ b/WebCore/html/ImageDocument.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ImageDocument_h
+#define ImageDocument_h
+
+#include "HTMLDocument.h"
+
+namespace WebCore {
+
+class ImageDocumentElement;
+
+class ImageDocument : public HTMLDocument {
+public:
+ static PassRefPtr<ImageDocument> create(Frame* frame, const KURL& url)
+ {
+ return adoptRef(new ImageDocument(frame, url));
+ }
+
+ CachedImage* cachedImage();
+ ImageDocumentElement* imageElement() const { return m_imageElement; }
+ void disconnectImageElement() { m_imageElement = 0; }
+
+ void windowSizeChanged();
+ void imageChanged();
+ void imageClicked(int x, int y);
+
+private:
+ ImageDocument(Frame*, const KURL&);
+
+ virtual PassRefPtr<DocumentParser> createParser();
+ virtual bool isImageDocument() const { return true; }
+
+ void createDocumentStructure();
+ void resizeImageToFit();
+ void restoreImageSize();
+ bool imageFitsInWindow() const;
+ bool shouldShrinkToFit() const;
+ float scale() const;
+
+ ImageDocumentElement* m_imageElement;
+
+ // Whether enough of the image has been loaded to determine its size
+ bool m_imageSizeIsKnown;
+
+ // Whether the image is shrunk to fit or not
+ bool m_didShrinkImage;
+
+ // Whether the image should be shrunk or not
+ bool m_shouldShrinkImage;
+};
+
+}
+
+#endif // ImageDocument_h
diff --git a/WebCore/html/MediaDocument.cpp b/WebCore/html/MediaDocument.cpp
new file mode 100644
index 0000000..875141b
--- /dev/null
+++ b/WebCore/html/MediaDocument.cpp
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(VIDEO)
+#include "MediaDocument.h"
+
+#include "DocumentLoader.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "FrameLoaderClient.h"
+#include "HTMLEmbedElement.h"
+#include "HTMLNames.h"
+#include "HTMLVideoElement.h"
+#include "KeyboardEvent.h"
+#include "MainResourceLoader.h"
+#include "NodeList.h"
+#include "RawDataDocumentParser.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// FIXME: Share more code with PluginDocumentParser.
+class MediaDocumentParser : public RawDataDocumentParser {
+public:
+ static PassRefPtr<MediaDocumentParser> create(MediaDocument* document)
+ {
+ return adoptRef(new MediaDocumentParser(document));
+ }
+
+private:
+ MediaDocumentParser(Document* document)
+ : RawDataDocumentParser(document)
+ , m_mediaElement(0)
+ {
+ }
+
+ virtual void appendBytes(DocumentWriter*, const char*, int, bool);
+
+ void createDocumentStructure();
+
+ HTMLMediaElement* m_mediaElement;
+};
+
+void MediaDocumentParser::createDocumentStructure()
+{
+ ExceptionCode ec;
+ RefPtr<Element> rootElement = document()->createElement(htmlTag, false);
+ document()->appendChild(rootElement, ec);
+
+ if (document()->frame())
+ document()->frame()->loader()->dispatchDocumentElementAvailable();
+
+ RefPtr<Element> body = document()->createElement(bodyTag, false);
+ body->setAttribute(styleAttr, "background-color: rgb(38,38,38);");
+
+ rootElement->appendChild(body, ec);
+
+ RefPtr<Element> mediaElement = document()->createElement(videoTag, false);
+
+ m_mediaElement = static_cast<HTMLVideoElement*>(mediaElement.get());
+ m_mediaElement->setAttribute(controlsAttr, "");
+ m_mediaElement->setAttribute(autoplayAttr, "");
+ m_mediaElement->setAttribute(styleAttr, "margin: auto; position: absolute; top: 0; right: 0; bottom: 0; left: 0;");
+
+ m_mediaElement->setAttribute(nameAttr, "media");
+ m_mediaElement->setSrc(document()->url());
+
+ body->appendChild(mediaElement, ec);
+
+ Frame* frame = document()->frame();
+ if (!frame)
+ return;
+
+ frame->loader()->activeDocumentLoader()->mainResourceLoader()->setShouldBufferData(false);
+}
+
+void MediaDocumentParser::appendBytes(DocumentWriter*, const char*, int, bool)
+{
+ ASSERT(!m_mediaElement);
+ if (m_mediaElement)
+ return;
+
+ createDocumentStructure();
+ finish();
+}
+
+MediaDocument::MediaDocument(Frame* frame, const KURL& url)
+ : HTMLDocument(frame, url)
+ , m_replaceMediaElementTimer(this, &MediaDocument::replaceMediaElementTimerFired)
+{
+ setCompatibilityMode(QuirksMode);
+ lockCompatibilityMode();
+}
+
+MediaDocument::~MediaDocument()
+{
+ ASSERT(!m_replaceMediaElementTimer.isActive());
+}
+
+PassRefPtr<DocumentParser> MediaDocument::createParser()
+{
+ return MediaDocumentParser::create(this);
+}
+
+void MediaDocument::defaultEventHandler(Event* event)
+{
+ // Match the default Quicktime plugin behavior to allow
+ // clicking and double-clicking to pause and play the media.
+ Node* targetNode = event->target()->toNode();
+ if (targetNode && targetNode->hasTagName(videoTag)) {
+ HTMLVideoElement* video = static_cast<HTMLVideoElement*>(targetNode);
+ if (event->type() == eventNames().clickEvent) {
+ if (!video->canPlay()) {
+ video->pause(event->fromUserGesture());
+ event->setDefaultHandled();
+ }
+ } else if (event->type() == eventNames().dblclickEvent) {
+ if (video->canPlay()) {
+ video->play(event->fromUserGesture());
+ event->setDefaultHandled();
+ }
+ }
+ }
+
+ if (event->type() == eventNames().keydownEvent && event->isKeyboardEvent()) {
+ HTMLVideoElement* video = 0;
+ if (targetNode) {
+ if (targetNode->hasTagName(videoTag))
+ video = static_cast<HTMLVideoElement*>(targetNode);
+ else {
+ RefPtr<NodeList> nodeList = targetNode->getElementsByTagName("video");
+ if (nodeList.get()->length() > 0)
+ video = static_cast<HTMLVideoElement*>(nodeList.get()->item(0));
+ }
+ }
+ if (video) {
+ KeyboardEvent* keyboardEvent = static_cast<KeyboardEvent*>(event);
+ if (keyboardEvent->keyIdentifier() == "U+0020") { // space
+ if (video->paused()) {
+ if (video->canPlay())
+ video->play(event->fromUserGesture());
+ } else
+ video->pause(event->fromUserGesture());
+ event->setDefaultHandled();
+ }
+ }
+ }
+}
+
+void MediaDocument::mediaElementSawUnsupportedTracks()
+{
+ // The HTMLMediaElement was told it has something that the underlying
+ // MediaPlayer cannot handle so we should switch from <video> to <embed>
+ // and let the plugin handle this. Don't do it immediately as this
+ // function may be called directly from a media engine callback, and
+ // replaceChild will destroy the element, media player, and media engine.
+ m_replaceMediaElementTimer.startOneShot(0);
+}
+
+void MediaDocument::replaceMediaElementTimerFired(Timer<MediaDocument>*)
+{
+ HTMLElement* htmlBody = body();
+ if (!htmlBody)
+ return;
+
+ // Set body margin width and height to 0 as that is what a PluginDocument uses.
+ htmlBody->setAttribute(marginwidthAttr, "0");
+ htmlBody->setAttribute(marginheightAttr, "0");
+
+ RefPtr<NodeList> nodeList = htmlBody->getElementsByTagName("video");
+
+ if (nodeList.get()->length() > 0) {
+ HTMLVideoElement* videoElement = static_cast<HTMLVideoElement*>(nodeList.get()->item(0));
+
+ RefPtr<Element> element = Document::createElement(embedTag, false);
+ HTMLEmbedElement* embedElement = static_cast<HTMLEmbedElement*>(element.get());
+
+ embedElement->setAttribute(widthAttr, "100%");
+ embedElement->setAttribute(heightAttr, "100%");
+ embedElement->setAttribute(nameAttr, "plugin");
+ embedElement->setAttribute(srcAttr, url().string());
+ embedElement->setAttribute(typeAttr, frame()->loader()->writer()->mimeType());
+
+ ExceptionCode ec;
+ videoElement->parent()->replaceChild(embedElement, videoElement, ec);
+ }
+}
+
+}
+#endif
diff --git a/WebCore/html/MediaDocument.h b/WebCore/html/MediaDocument.h
new file mode 100644
index 0000000..2d81296
--- /dev/null
+++ b/WebCore/html/MediaDocument.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2008,2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MediaDocument_h
+#define MediaDocument_h
+
+#if ENABLE(VIDEO)
+
+#include "HTMLDocument.h"
+
+namespace WebCore {
+
+class MediaDocument : public HTMLDocument {
+public:
+ static PassRefPtr<MediaDocument> create(Frame* frame, const KURL& url)
+ {
+ return adoptRef(new MediaDocument(frame, url));
+ }
+ virtual ~MediaDocument();
+
+ void mediaElementSawUnsupportedTracks();
+
+private:
+ MediaDocument(Frame*, const KURL&);
+
+ virtual bool isMediaDocument() const { return true; }
+ virtual PassRefPtr<DocumentParser> createParser();
+
+ virtual void defaultEventHandler(Event*);
+
+ void replaceMediaElementTimerFired(Timer<MediaDocument>*);
+
+ Timer<MediaDocument> m_replaceMediaElementTimer;
+};
+
+}
+
+#endif
+#endif
diff --git a/WebCore/html/PluginDocument.cpp b/WebCore/html/PluginDocument.cpp
new file mode 100644
index 0000000..ad11dfb
--- /dev/null
+++ b/WebCore/html/PluginDocument.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PluginDocument.h"
+
+#include "DocumentLoader.h"
+#include "Frame.h"
+#include "FrameLoaderClient.h"
+#include "HTMLEmbedElement.h"
+#include "HTMLNames.h"
+#include "MainResourceLoader.h"
+#include "Page.h"
+#include "RawDataDocumentParser.h"
+#include "RenderEmbeddedObject.h"
+#include "Settings.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// FIXME: Share more code with MediaDocumentParser.
+class PluginDocumentParser : public RawDataDocumentParser {
+public:
+ static PassRefPtr<PluginDocumentParser> create(PluginDocument* document)
+ {
+ return adoptRef(new PluginDocumentParser(document));
+ }
+
+ static Widget* pluginWidgetFromDocument(Document*);
+
+private:
+ PluginDocumentParser(Document* document)
+ : RawDataDocumentParser(document)
+ , m_embedElement(0)
+ {
+ }
+
+ virtual void appendBytes(DocumentWriter*, const char*, int, bool);
+
+ void createDocumentStructure();
+
+ HTMLEmbedElement* m_embedElement;
+};
+
+Widget* PluginDocumentParser::pluginWidgetFromDocument(Document* doc)
+{
+ ASSERT(doc);
+ RefPtr<Element> body = doc->body();
+ if (body) {
+ RefPtr<Node> node = body->firstChild();
+ if (node && node->renderer()) {
+ ASSERT(node->renderer()->isEmbeddedObject());
+ return toRenderEmbeddedObject(node->renderer())->widget();
+ }
+ }
+ return 0;
+}
+
+void PluginDocumentParser::createDocumentStructure()
+{
+ ExceptionCode ec;
+ RefPtr<Element> rootElement = document()->createElement(htmlTag, false);
+ document()->appendChild(rootElement, ec);
+
+ if (document()->frame() && document()->frame()->loader())
+ document()->frame()->loader()->dispatchDocumentElementAvailable();
+
+ RefPtr<Element> body = document()->createElement(bodyTag, false);
+ body->setAttribute(marginwidthAttr, "0");
+ body->setAttribute(marginheightAttr, "0");
+ body->setAttribute(bgcolorAttr, "rgb(38,38,38)");
+
+ rootElement->appendChild(body, ec);
+
+ RefPtr<Element> embedElement = document()->createElement(embedTag, false);
+
+ m_embedElement = static_cast<HTMLEmbedElement*>(embedElement.get());
+ m_embedElement->setAttribute(widthAttr, "100%");
+ m_embedElement->setAttribute(heightAttr, "100%");
+
+ m_embedElement->setAttribute(nameAttr, "plugin");
+ m_embedElement->setAttribute(srcAttr, document()->url().string());
+ m_embedElement->setAttribute(typeAttr, document()->frame()->loader()->writer()->mimeType());
+
+ body->appendChild(embedElement, ec);
+}
+
+void PluginDocumentParser::appendBytes(DocumentWriter*, const char*, int, bool)
+{
+ ASSERT(!m_embedElement);
+ if (m_embedElement)
+ return;
+
+ createDocumentStructure();
+
+ Frame* frame = document()->frame();
+ if (!frame)
+ return;
+ Settings* settings = frame->settings();
+ if (!settings || !frame->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin))
+ return;
+
+ document()->updateLayout();
+
+ if (RenderPart* renderer = m_embedElement->renderPart()) {
+ frame->loader()->client()->redirectDataToPlugin(renderer->widget());
+ frame->loader()->activeDocumentLoader()->mainResourceLoader()->setShouldBufferData(false);
+ }
+
+ finish();
+}
+
+PluginDocument::PluginDocument(Frame* frame, const KURL& url)
+ : HTMLDocument(frame, url)
+{
+ setCompatibilityMode(QuirksMode);
+ lockCompatibilityMode();
+}
+
+PassRefPtr<DocumentParser> PluginDocument::createParser()
+{
+ return PluginDocumentParser::create(this);
+}
+
+Widget* PluginDocument::pluginWidget()
+{
+ return PluginDocumentParser::pluginWidgetFromDocument(this);
+}
+
+Node* PluginDocument::pluginNode()
+{
+ RefPtr<Element> body_element = body();
+ if (body_element)
+ return body_element->firstChild();
+
+ return 0;
+}
+
+}
diff --git a/WebCore/html/PluginDocument.h b/WebCore/html/PluginDocument.h
new file mode 100644
index 0000000..3bb5d99
--- /dev/null
+++ b/WebCore/html/PluginDocument.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2006, 2008, 2009Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PluginDocument_h
+#define PluginDocument_h
+
+#include "HTMLDocument.h"
+
+namespace WebCore {
+
+class Node;
+class Widget;
+class PluginDocument : public HTMLDocument {
+public:
+ static PassRefPtr<PluginDocument> create(Frame* frame, const KURL& url)
+ {
+ return adoptRef(new PluginDocument(frame, url));
+ }
+
+ Widget* pluginWidget();
+ Node* pluginNode();
+
+ virtual bool isPluginDocument() const { return true; }
+
+private:
+ PluginDocument(Frame*, const KURL&);
+
+ virtual PassRefPtr<DocumentParser> createParser();
+};
+
+}
+
+#endif // PluginDocument_h
diff --git a/WebCore/html/TextDocument.cpp b/WebCore/html/TextDocument.cpp
new file mode 100644
index 0000000..9334a39
--- /dev/null
+++ b/WebCore/html/TextDocument.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TextDocument.h"
+
+#include "TextDocumentParser.h"
+
+namespace WebCore {
+
+TextDocument::TextDocument(Frame* frame, const KURL& url)
+ : HTMLDocument(frame, url)
+{
+ setCompatibilityMode(QuirksMode);
+ lockCompatibilityMode();
+}
+
+PassRefPtr<DocumentParser> TextDocument::createParser()
+{
+ return TextDocumentParser::create(this);
+}
+
+}
diff --git a/WebCore/html/TextDocument.h b/WebCore/html/TextDocument.h
new file mode 100644
index 0000000..2ea49f8
--- /dev/null
+++ b/WebCore/html/TextDocument.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2006, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TextDocument_h
+#define TextDocument_h
+
+#include "HTMLDocument.h"
+
+namespace WebCore {
+
+class TextDocument : public HTMLDocument {
+public:
+ static PassRefPtr<TextDocument> create(Frame* frame, const KURL& url)
+ {
+ return adoptRef(new TextDocument(frame, url));
+ }
+
+private:
+ TextDocument(Frame*, const KURL&);
+
+ virtual PassRefPtr<DocumentParser> createParser();
+};
+
+}
+
+#endif
diff --git a/WebCore/html/canvas/ArrayBufferView.cpp b/WebCore/html/canvas/ArrayBufferView.cpp
index bd22f88..485d18b 100644
--- a/WebCore/html/canvas/ArrayBufferView.cpp
+++ b/WebCore/html/canvas/ArrayBufferView.cpp
@@ -59,6 +59,34 @@ void ArrayBufferView::setImpl(ArrayBufferView* array, unsigned byteOffset, Excep
memmove(base + byteOffset, array->baseAddress(), array->byteLength());
}
+void ArrayBufferView::setRangeImpl(const char* data, size_t dataByteLength, unsigned byteOffset, ExceptionCode& ec)
+{
+ if (byteOffset > byteLength()
+ || byteOffset + dataByteLength > byteLength()
+ || byteOffset + dataByteLength < byteOffset) {
+ // Out of range offset or overflow
+ ec = INDEX_SIZE_ERR;
+ return;
+ }
+
+ char* base = static_cast<char*>(baseAddress());
+ memmove(base + byteOffset, data, dataByteLength);
+}
+
+void ArrayBufferView::zeroRangeImpl(unsigned byteOffset, size_t rangeByteLength, ExceptionCode& ec)
+{
+ if (byteOffset > byteLength()
+ || byteOffset + rangeByteLength > byteLength()
+ || byteOffset + rangeByteLength < byteOffset) {
+ // Out of range offset or overflow
+ ec = INDEX_SIZE_ERR;
+ return;
+ }
+
+ char* base = static_cast<char*>(baseAddress());
+ memset(base + byteOffset, 0, rangeByteLength);
+}
+
void ArrayBufferView::calculateOffsetAndLength(int start, int end, unsigned arraySize,
unsigned* offset, unsigned* length)
{
diff --git a/WebCore/html/canvas/ArrayBufferView.h b/WebCore/html/canvas/ArrayBufferView.h
index 29ad691..ee685b1 100644
--- a/WebCore/html/canvas/ArrayBufferView.h
+++ b/WebCore/html/canvas/ArrayBufferView.h
@@ -73,6 +73,10 @@ class ArrayBufferView : public RefCounted<ArrayBufferView> {
void setImpl(ArrayBufferView* array, unsigned byteOffset, ExceptionCode& ec);
+ void setRangeImpl(const char* data, size_t dataByteLength, unsigned byteOffset, ExceptionCode& ec);
+
+ void zeroRangeImpl(unsigned byteOffset, size_t rangeByteLength, ExceptionCode& ec);
+
static void calculateOffsetAndLength(int start, int end, unsigned arraySize,
unsigned* offset, unsigned* length);
diff --git a/WebCore/html/canvas/CanvasRenderingContext.cpp b/WebCore/html/canvas/CanvasRenderingContext.cpp
index 1e897d3..e019332 100644
--- a/WebCore/html/canvas/CanvasRenderingContext.cpp
+++ b/WebCore/html/canvas/CanvasRenderingContext.cpp
@@ -25,9 +25,6 @@
#include "config.h"
#include "CanvasRenderingContext.h"
-#if ENABLE(ACCELERATED_2D_CANVAS) || ENABLE(3D_CANVAS)
-#include "GraphicsContext3D.h"
-#endif
#include "HTMLCanvasElement.h"
namespace WebCore {
@@ -47,13 +44,4 @@ void CanvasRenderingContext::deref()
m_canvas->deref();
}
-bool CanvasRenderingContext::paintsIntoCanvasBuffer() const
-{
-#if ENABLE(ACCELERATED_2D_CANVAS) || ENABLE(3D_CANVAS)
- if (GraphicsContext3D* context3D = graphicsContext3D())
- return context3D->paintsIntoCanvasBuffer();
-#endif
- return true;
-}
-
} // namespace WebCore
diff --git a/WebCore/html/canvas/CanvasRenderingContext.h b/WebCore/html/canvas/CanvasRenderingContext.h
index 2cdbe1d..8499b47 100644
--- a/WebCore/html/canvas/CanvasRenderingContext.h
+++ b/WebCore/html/canvas/CanvasRenderingContext.h
@@ -26,12 +26,13 @@
#ifndef CanvasRenderingContext_h
#define CanvasRenderingContext_h
+#include "GraphicsLayer.h"
+
#include <wtf/Noncopyable.h>
namespace WebCore {
class WebGLObject;
- class GraphicsContext3D;
class HTMLCanvasElement;
class CanvasRenderingContext : public Noncopyable {
@@ -49,12 +50,12 @@ namespace WebCore {
virtual bool is3d() const { return false; }
virtual bool isAccelerated() const { return false; }
- // For accelerated canvases, returns a pointer to the underlying GraphicsContext3D.
- // For non accelerated canvases returns 0.
- virtual GraphicsContext3D* graphicsContext3D() const { return 0; }
-
virtual void paintRenderingResultsToCanvas() {}
- bool paintsIntoCanvasBuffer() const;
+ virtual bool paintsIntoCanvasBuffer() const { return true; }
+
+#if USE(ACCELERATED_COMPOSITING)
+ virtual PlatformLayer* platformLayer() const { return 0; }
+#endif
private:
HTMLCanvasElement* m_canvas;
diff --git a/WebCore/html/canvas/CanvasRenderingContext2D.cpp b/WebCore/html/canvas/CanvasRenderingContext2D.cpp
index 6df6abf..338960c 100644..100755
--- a/WebCore/html/canvas/CanvasRenderingContext2D.cpp
+++ b/WebCore/html/canvas/CanvasRenderingContext2D.cpp
@@ -25,7 +25,7 @@
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
@@ -59,8 +59,12 @@
#include "TextMetrics.h"
#if ENABLE(ACCELERATED_2D_CANVAS)
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "DrawingBuffer.h"
#include "FrameView.h"
#include "GraphicsContext3D.h"
+#include "SharedGraphicsContext3D.h"
#if USE(ACCELERATED_COMPOSITING)
#include "RenderLayer.h"
#endif
@@ -124,17 +128,11 @@ CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, bo
return;
if (!p->settings()->accelerated2dCanvasEnabled())
return;
- if (FrameView* view = canvas->document()->view()) {
- if (ScrollView* rootView = view->root()) {
- if (HostWindow* hostWindow = rootView->hostWindow()) {
- // Set up our context
- GraphicsContext3D::Attributes attr;
- attr.stencil = true;
- m_context3D = GraphicsContext3D::create(attr, hostWindow);
- if (m_context3D)
- if (GraphicsContext* c = drawingContext())
- c->setGraphicsContext3D(m_context3D.get(), IntSize(canvas->width(), canvas->height()));
- }
+ m_context3D = p->chrome()->client()->getSharedGraphicsContext3D();
+ if (m_context3D) {
+ if (GraphicsContext* c = drawingContext()) {
+ m_drawingBuffer = DrawingBuffer::create(m_context3D.get(), IntSize(canvas->width(), canvas->height()));
+ c->setSharedGraphicsContext3D(m_context3D.get(), m_drawingBuffer.get(), IntSize(canvas->width(), canvas->height()));
}
}
#endif
@@ -153,6 +151,16 @@ bool CanvasRenderingContext2D::isAccelerated() const
#endif
}
+bool CanvasRenderingContext2D::paintsIntoCanvasBuffer() const
+{
+#if ENABLE(ACCELERATED_2D_CANVAS)
+ if (m_context3D)
+ return m_context3D->paintsIntoCanvasBuffer();
+#endif
+ return true;
+}
+
+
void CanvasRenderingContext2D::reset()
{
m_stateStack.resize(1);
@@ -160,8 +168,10 @@ void CanvasRenderingContext2D::reset()
m_path.clear();
#if ENABLE(ACCELERATED_2D_CANVAS)
if (m_context3D) {
- if (GraphicsContext* c = drawingContext())
- c->setGraphicsContext3D(m_context3D.get(), IntSize(canvas()->width(), canvas()->height()));
+ if (GraphicsContext* c = drawingContext()) {
+ m_drawingBuffer->reset(IntSize(canvas()->width(), canvas()->height()));
+ c->setSharedGraphicsContext3D(m_context3D.get(), m_drawingBuffer.get(), IntSize(canvas()->width(), canvas()->height()));
+ }
}
#endif
}
@@ -209,7 +219,7 @@ void CanvasRenderingContext2D::restore()
c->restore();
}
-void CanvasRenderingContext2D::setAllAttributesToDefault()
+void CanvasRenderingContext2D::setAllAttributesToDefault()
{
state().m_globalAlpha = 1;
state().m_shadowOffset = FloatSize();
@@ -431,6 +441,15 @@ void CanvasRenderingContext2D::setGlobalCompositeOperation(const String& operati
if (!c)
return;
c->setCompositeOperation(op);
+#if ENABLE(ACCELERATED_2D_CANVAS)
+ if (isAccelerated() && op != CompositeSourceOver) {
+ c->setSharedGraphicsContext3D(0, 0, IntSize());
+ m_drawingBuffer.clear();
+ m_context3D.clear();
+ // Mark as needing a style recalc so our compositing layer can be removed.
+ canvas()->setNeedsStyleRecalc(SyntheticStyleChange);
+ }
+#endif
}
void CanvasRenderingContext2D::scale(float sx, float sy)
@@ -640,7 +659,7 @@ void CanvasRenderingContext2D::closePath()
FloatRect boundRect = m_path.boundingRect();
if (boundRect.width() || boundRect.height())
- m_path.closeSubpath();
+ m_path.closeCanvasSubpath();
}
void CanvasRenderingContext2D::moveTo(float x, float y)
@@ -924,7 +943,7 @@ void CanvasRenderingContext2D::strokeRect(float x, float y, float width, float h
{
if (!validateRectForCanvas(x, y, width, height))
return;
-
+
if (!(lineWidth >= 0))
return;
@@ -1257,7 +1276,7 @@ void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, const
return;
if (!state().m_invertibleCTM)
return;
-
+
FloatRect sourceRect = c->roundToDevicePixels(srcRect);
FloatRect destRect = c->roundToDevicePixels(dstRect);
@@ -1269,7 +1288,16 @@ void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, const
if (!sourceCanvas->originClean())
canvas()->setOriginTainted();
+#if ENABLE(ACCELERATED_2D_CANVAS)
+ // If we're drawing from one accelerated canvas 2d to another, avoid calling sourceCanvas->makeRenderingResultsAvailable()
+ // as that will do a readback to software.
+ CanvasRenderingContext* sourceContext = sourceCanvas->renderingContext();
+ // FIXME: Implement an accelerated path for drawing from a WebGL canvas to a 2d canvas when possible.
+ if (!isAccelerated() || !sourceContext || !sourceContext->isAccelerated() || !sourceContext->is2d())
+ sourceCanvas->makeRenderingResultsAvailable();
+#else
sourceCanvas->makeRenderingResultsAvailable();
+#endif
c->drawImageBuffer(buffer, DeviceColorSpace, destRect, sourceRect, state().m_globalComposite);
didDraw(destRect);
@@ -1482,12 +1510,12 @@ void CanvasRenderingContext2D::didDraw(const FloatRect& r, unsigned options)
return;
FloatRect dirtyRect = r;
- if (options & CanvasWillDrawApplyTransform) {
+ if (options & CanvasDidDrawApplyTransform) {
AffineTransform ctm = state().m_transform;
dirtyRect = ctm.mapRect(r);
}
- if (options & CanvasWillDrawApplyShadow && alphaChannel(state().m_shadowColor)) {
+ if (options & CanvasDidDrawApplyShadow && alphaChannel(state().m_shadowColor)) {
// The shadow gets applied after transformation
FloatRect shadowRect(dirtyRect);
shadowRect.move(state().m_shadowOffset);
@@ -1495,16 +1523,20 @@ void CanvasRenderingContext2D::didDraw(const FloatRect& r, unsigned options)
dirtyRect.unite(shadowRect);
}
- if (options & CanvasWillDrawApplyClip) {
+ if (options & CanvasDidDrawApplyClip) {
// FIXME: apply the current clip to the rectangle. Unfortunately we can't get the clip
// back out of the GraphicsContext, so to take clip into account for incremental painting,
// we'd have to keep the clip path around.
}
+#if ENABLE(ACCELERATED_2D_CANVAS)
+ if (isAccelerated())
+ drawingContext()->markDirtyRect(enclosingIntRect(dirtyRect));
+#endif
#if ENABLE(ACCELERATED_2D_CANVAS) && USE(ACCELERATED_COMPOSITING)
// If we are drawing to hardware and we have a composited layer, just call rendererContentChanged().
RenderBox* renderBox = canvas()->renderBox();
- if (m_context3D && renderBox && renderBox->hasLayer() && renderBox->layer()->hasAcceleratedCompositing())
+ if (isAccelerated() && renderBox && renderBox->hasLayer() && renderBox->layer()->hasAcceleratedCompositing())
renderBox->layer()->rendererContentChanged();
else
#endif
@@ -1577,7 +1609,7 @@ PassRefPtr<ImageData> CanvasRenderingContext2D::getImageData(float sx, float sy,
scaledRect.setWidth(1);
if (scaledRect.height() < 1)
scaledRect.setHeight(1);
- ImageBuffer* buffer = canvas() ? canvas()->buffer() : 0;
+ ImageBuffer* buffer = canvas()->buffer();
if (!buffer)
return createEmptyImageData(scaledRect.size());
return buffer->getUnmultipliedImageData(scaledRect);
@@ -1630,7 +1662,7 @@ void CanvasRenderingContext2D::putImageData(ImageData* data, float dx, float dy,
IntPoint destPoint(destOffset.width(), destOffset.height());
buffer->putUnmultipliedImageData(data, sourceRect, destPoint);
- didDraw(sourceRect, 0); // ignore transform, shadow and clip
+ didDraw(sourceRect, CanvasDidDrawApplyNone); // ignore transform, shadow and clip
}
String CanvasRenderingContext2D::font() const
@@ -1850,11 +1882,11 @@ void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, flo
c->drawBidiText(font, textRun, location);
if (fill)
- canvas()->didDraw(textRect);
+ didDraw(textRect);
else {
// When stroking text, pointy miters can extend outside of textRect, so we
// punt and dirty the whole canvas.
- canvas()->didDraw(FloatRect(0, 0, canvas()->width(), canvas()->height()));
+ didDraw(FloatRect(0, 0, canvas()->width(), canvas()->height()));
}
#if PLATFORM(QT)
@@ -1877,4 +1909,11 @@ void CanvasRenderingContext2D::paintRenderingResultsToCanvas()
#endif
}
+#if ENABLE(ACCELERATED_2D_CANVAS) && USE(ACCELERATED_COMPOSITING)
+PlatformLayer* CanvasRenderingContext2D::platformLayer() const
+{
+ return m_drawingBuffer->platformLayer();
+}
+#endif
+
} // namespace WebCore
diff --git a/WebCore/html/canvas/CanvasRenderingContext2D.h b/WebCore/html/canvas/CanvasRenderingContext2D.h
index 9857344..91b6549 100644
--- a/WebCore/html/canvas/CanvasRenderingContext2D.h
+++ b/WebCore/html/canvas/CanvasRenderingContext2D.h
@@ -20,7 +20,7 @@
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CanvasRenderingContext2D_h
@@ -61,7 +61,8 @@ class KURL;
class TextMetrics;
#if ENABLE(ACCELERATED_2D_CANVAS)
-class GraphicsContext3D;
+class DrawingBuffer;
+class SharedGraphicsContext3D;
#endif
typedef int ExceptionCode;
@@ -74,6 +75,7 @@ public:
virtual bool is2d() const { return true; }
virtual bool isAccelerated() const;
+ virtual bool paintsIntoCanvasBuffer() const;
CanvasStyle* strokeStyle() const;
void setStrokeStyle(PassRefPtr<CanvasStyle>);
@@ -223,8 +225,8 @@ public:
virtual void paintRenderingResultsToCanvas();
-#if ENABLE(ACCELERATED_2D_CANVAS)
- virtual GraphicsContext3D* graphicsContext3D() const { return m_context3D.get(); }
+#if ENABLE(ACCELERATED_2D_CANVAS) && USE(ACCELERATED_COMPOSITING)
+ virtual PlatformLayer* platformLayer() const;
#endif
private:
@@ -262,14 +264,15 @@ private:
void applyShadow();
- enum CanvasWillDrawOption {
- CanvasWillDrawApplyTransform = 1,
- CanvasWillDrawApplyShadow = 1 << 1,
- CanvasWillDrawApplyClip = 1 << 2,
- CanvasWillDrawApplyAll = 0xffffffff
+ enum CanvasDidDrawOption {
+ CanvasDidDrawApplyNone = 0,
+ CanvasDidDrawApplyTransform = 1,
+ CanvasDidDrawApplyShadow = 1 << 1,
+ CanvasDidDrawApplyClip = 1 << 2,
+ CanvasDidDrawApplyAll = 0xffffffff
};
- void didDraw(const FloatRect&, unsigned options = CanvasWillDrawApplyAll);
+ void didDraw(const FloatRect&, unsigned options = CanvasDidDrawApplyAll);
GraphicsContext* drawingContext() const;
@@ -298,7 +301,8 @@ private:
#endif
#if ENABLE(ACCELERATED_2D_CANVAS)
- OwnPtr<GraphicsContext3D> m_context3D;
+ OwnPtr<DrawingBuffer> m_drawingBuffer;
+ RefPtr<SharedGraphicsContext3D> m_context3D;
#endif
};
diff --git a/WebCore/html/canvas/TypedArrayBase.h b/WebCore/html/canvas/TypedArrayBase.h
index e69c2b5..77283df 100644
--- a/WebCore/html/canvas/TypedArrayBase.h
+++ b/WebCore/html/canvas/TypedArrayBase.h
@@ -42,6 +42,16 @@ class TypedArrayBase : public ArrayBufferView {
setImpl(array, offset * sizeof(T), ec);
}
+ void setRange(const T* data, size_t dataLength, unsigned offset, ExceptionCode& ec)
+ {
+ setRangeImpl(reinterpret_cast<const char*>(data), dataLength * sizeof(T), offset * sizeof(T), ec);
+ }
+
+ void zeroRange(unsigned offset, size_t length, ExceptionCode& ec)
+ {
+ zeroRangeImpl(offset * sizeof(T), length * sizeof(T), ec);
+ }
+
// Overridden from ArrayBufferView. This must be public because of
// rules about inheritance of members in template classes, and
// because it is accessed via pointers to subclasses.
diff --git a/WebCore/html/canvas/WebGLRenderingContext.cpp b/WebCore/html/canvas/WebGLRenderingContext.cpp
index 2a1464a..bda3569 100644
--- a/WebCore/html/canvas/WebGLRenderingContext.cpp
+++ b/WebCore/html/canvas/WebGLRenderingContext.cpp
@@ -170,6 +170,11 @@ void WebGLRenderingContext::paintRenderingResultsToCanvas()
m_context->paintRenderingResultsToCanvas(this);
}
+bool WebGLRenderingContext::paintsIntoCanvasBuffer() const
+{
+ return m_context->paintsIntoCanvasBuffer();
+}
+
void WebGLRenderingContext::reshape(int width, int height)
{
if (m_needsUpdate) {
diff --git a/WebCore/html/canvas/WebGLRenderingContext.h b/WebCore/html/canvas/WebGLRenderingContext.h
index 66ec8d8..d812c69 100644
--- a/WebCore/html/canvas/WebGLRenderingContext.h
+++ b/WebCore/html/canvas/WebGLRenderingContext.h
@@ -63,6 +63,7 @@ public:
virtual bool is3d() const { return true; }
virtual bool isAccelerated() const { return true; }
+ virtual bool paintsIntoCanvasBuffer() const;
void activeTexture(unsigned long texture, ExceptionCode& ec);
void attachShader(WebGLProgram*, WebGLShader*, ExceptionCode& ec);
@@ -277,7 +278,10 @@ public:
void viewport(long x, long y, unsigned long width, unsigned long height);
- virtual GraphicsContext3D* graphicsContext3D() const { return m_context.get(); }
+ GraphicsContext3D* graphicsContext3D() const { return m_context.get(); }
+#if USE(ACCELERATED_COMPOSITING)
+ virtual PlatformLayer* platformLayer() const { return m_context->platformLayer(); }
+#endif
void reshape(int width, int height);
diff --git a/WebCore/html/parser/CSSPreloadScanner.cpp b/WebCore/html/parser/CSSPreloadScanner.cpp
index 729103e..6ac923d 100644
--- a/WebCore/html/parser/CSSPreloadScanner.cpp
+++ b/WebCore/html/parser/CSSPreloadScanner.cpp
@@ -30,7 +30,7 @@
#include "CSSHelper.h"
#include "CachedCSSStyleSheet.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
#include "Document.h"
#include "HTMLToken.h"
@@ -151,7 +151,7 @@ void CSSPreloadScanner::emitRule()
String value(m_ruleValue.data(), m_ruleValue.size());
String url = deprecatedParseURL(value);
if (!url.isEmpty())
- m_document->docLoader()->preload(CachedResource::CSSStyleSheet, url, String(), m_scanningBody);
+ m_document->cachedResourceLoader()->preload(CachedResource::CSSStyleSheet, url, String(), m_scanningBody);
}
m_rule.clear();
m_ruleValue.clear();
diff --git a/WebCore/html/parser/HTMLConstructionSite.cpp b/WebCore/html/parser/HTMLConstructionSite.cpp
index 975b1af..0172b3d 100644
--- a/WebCore/html/parser/HTMLConstructionSite.cpp
+++ b/WebCore/html/parser/HTMLConstructionSite.cpp
@@ -213,7 +213,7 @@ void HTMLConstructionSite::insertDoctype(AtomicHTMLToken& token)
void HTMLConstructionSite::insertComment(AtomicHTMLToken& token)
{
ASSERT(token.type() == HTMLToken::Comment);
- attach(currentElement(), Comment::create(m_document, token.comment()));
+ attach(currentElement(), Comment::create(currentElement()->document(), token.comment()));
}
void HTMLConstructionSite::insertCommentOnDocument(AtomicHTMLToken& token)
@@ -225,7 +225,8 @@ void HTMLConstructionSite::insertCommentOnDocument(AtomicHTMLToken& token)
void HTMLConstructionSite::insertCommentOnHTMLHtmlElement(AtomicHTMLToken& token)
{
ASSERT(token.type() == HTMLToken::Comment);
- attach(m_openElements.htmlElement(), Comment::create(m_document, token.comment()));
+ Element* parent = m_openElements.htmlElement();
+ attach(parent, Comment::create(parent->document(), token.comment()));
}
PassRefPtr<Element> HTMLConstructionSite::attachToCurrent(PassRefPtr<Element> child)
@@ -293,7 +294,7 @@ void HTMLConstructionSite::insertFormattingElement(AtomicHTMLToken& token)
void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken& token)
{
- RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, m_document, true);
+ RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, currentElement()->document(), true);
if (m_fragmentScriptingPermission == FragmentScriptingAllowed)
element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission);
m_openElements.push(attachToCurrent(element.release()));
@@ -326,13 +327,13 @@ void HTMLConstructionSite::insertTextNode(const String& characters)
return;
}
- attachAtSite(site, Text::create(m_document, characters));
+ attachAtSite(site, Text::create(site.parent->document(), characters));
}
PassRefPtr<Element> HTMLConstructionSite::createElement(AtomicHTMLToken& token, const AtomicString& namespaceURI)
{
QualifiedName tagName(nullAtom, token.name(), namespaceURI);
- RefPtr<Element> element = m_document->createElement(tagName, true);
+ RefPtr<Element> element = currentElement()->document()->createElement(tagName, true);
element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission);
return element.release();
}
@@ -343,7 +344,7 @@ PassRefPtr<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken& tok
// FIXME: This can't use HTMLConstructionSite::createElement because we
// have to pass the current form element. We should rework form association
// to occur after construction to allow better code sharing here.
- RefPtr<Element> element = HTMLElementFactory::createHTMLElement(tagName, m_document, form(), true);
+ RefPtr<Element> element = HTMLElementFactory::createHTMLElement(tagName, currentElement()->document(), form(), true);
element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission);
ASSERT(element->isHTMLElement());
return element.release();
diff --git a/WebCore/html/parser/HTMLDocumentParser.cpp b/WebCore/html/parser/HTMLDocumentParser.cpp
index 0a1208d..a442d54 100644
--- a/WebCore/html/parser/HTMLDocumentParser.cpp
+++ b/WebCore/html/parser/HTMLDocumentParser.cpp
@@ -146,6 +146,32 @@ void HTMLDocumentParser::stopParsing()
m_parserScheduler.clear(); // Deleting the scheduler will clear any timers.
}
+// This kicks off "Once the user agent stops parsing" as described by:
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#the-end
+void HTMLDocumentParser::prepareToStopParsing()
+{
+ ASSERT(!hasInsertionPoint());
+
+ // pumpTokenizer can cause this parser to be detached from the Document,
+ // but we need to ensure it isn't deleted yet.
+ RefPtr<HTMLDocumentParser> protect(this);
+
+ // NOTE: This pump should only ever emit buffered character tokens,
+ // so ForceSynchronous vs. AllowYield should be meaningless.
+ pumpTokenizerIfPossible(ForceSynchronous);
+
+ if (isStopped())
+ return;
+
+ DocumentParser::prepareToStopParsing();
+
+ // We will not have a scriptRunner when parsing a DocumentFragment.
+ if (m_scriptRunner)
+ document()->setReadyState(Document::Interactive);
+
+ attemptToRunDeferredScriptsAndEnd();
+}
+
bool HTMLDocumentParser::processingData() const
{
return isScheduledForResume() || inWrite();
@@ -153,7 +179,7 @@ bool HTMLDocumentParser::processingData() const
void HTMLDocumentParser::pumpTokenizerIfPossible(SynchronousMode mode)
{
- if (m_parserStopped || m_treeBuilder->isPaused())
+ if (isStopped() || m_treeBuilder->isPaused())
return;
// Once a resume is scheduled, HTMLParserScheduler controls when we next pump.
@@ -197,8 +223,7 @@ bool HTMLDocumentParser::runScriptsForPausedTreeBuilder()
void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
{
- ASSERT(!isDetached());
- ASSERT(!m_parserStopped);
+ ASSERT(!isStopped());
ASSERT(!m_treeBuilder->isPaused());
ASSERT(!isScheduledForResume());
// ASSERT that this object is both attached to the Document and protected.
@@ -218,7 +243,7 @@ void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
m_token.clear();
// JavaScript may have stopped or detached the parser.
- if (isDetached() || m_parserStopped)
+ if (isStopped())
return;
// The parser will pause itself when waiting on a script to load or run.
@@ -230,7 +255,7 @@ void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode)
m_treeBuilder->setPaused(!shouldContinueParsing);
// JavaScript may have stopped or detached the parser.
- if (isDetached() || m_parserStopped)
+ if (isStopped())
return;
if (!shouldContinueParsing)
@@ -279,7 +304,7 @@ bool HTMLDocumentParser::hasInsertionPoint()
void HTMLDocumentParser::insert(const SegmentedString& source)
{
- if (m_parserStopped)
+ if (isStopped())
return;
#ifdef ANDROID_INSTRUMENT
@@ -304,7 +329,7 @@ void HTMLDocumentParser::insert(const SegmentedString& source)
void HTMLDocumentParser::append(const SegmentedString& source)
{
- if (m_parserStopped)
+ if (isStopped())
return;
// pumpTokenizer can cause this parser to be detached from the Document,
@@ -342,18 +367,19 @@ void HTMLDocumentParser::end()
ASSERT(!isDetached());
ASSERT(!isScheduledForResume());
- // pumpTokenizer can cause this parser to be detached from the Document,
- // but we need to ensure it isn't deleted yet.
- RefPtr<HTMLDocumentParser> protect(this);
-
- // NOTE: This pump should only ever emit buffered character tokens,
- // so ForceSynchronous vs. AllowYield should be meaningless.
- pumpTokenizerIfPossible(ForceSynchronous);
-
// Informs the the rest of WebCore that parsing is really finished (and deletes this).
m_treeBuilder->finished();
}
+void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd()
+{
+ ASSERT(isStopping());
+ ASSERT(!hasInsertionPoint());
+ if (m_scriptRunner && !m_scriptRunner->executeScriptsWaitingForParsing())
+ return;
+ end();
+}
+
void HTMLDocumentParser::attemptToEnd()
{
// finish() indicates we will not receive any more data. If we are waiting on
@@ -363,7 +389,7 @@ void HTMLDocumentParser::attemptToEnd()
m_endWasDelayed = true;
return;
}
- end();
+ prepareToStopParsing();
}
void HTMLDocumentParser::endIfDelayed()
@@ -376,7 +402,7 @@ void HTMLDocumentParser::endIfDelayed()
return;
m_endWasDelayed = false;
- end();
+ prepareToStopParsing();
}
void HTMLDocumentParser::finish()
@@ -467,6 +493,11 @@ void HTMLDocumentParser::notifyFinished(CachedResource* cachedResource)
ASSERT(m_scriptRunner);
ASSERT(!inScriptExecution());
+ if (isStopping()) {
+ attemptToRunDeferredScriptsAndEnd();
+ return;
+ }
+
ASSERT(m_treeBuilder->isPaused());
// Note: We only ever wait on one script at a time, so we always know this
// is the one we were waiting on and can un-pause the tree builder.
diff --git a/WebCore/html/parser/HTMLDocumentParser.h b/WebCore/html/parser/HTMLDocumentParser.h
index da21a2b..6d5b6d7 100644
--- a/WebCore/html/parser/HTMLDocumentParser.h
+++ b/WebCore/html/parser/HTMLDocumentParser.h
@@ -69,18 +69,22 @@ public:
protected:
virtual void insert(const SegmentedString&);
+ virtual void append(const SegmentedString&);
virtual void finish();
HTMLDocumentParser(HTMLDocument*, bool reportErrors);
HTMLDocumentParser(DocumentFragment*, Element* contextElement, FragmentScriptingPermission);
+ HTMLTokenizer* tokenizer() const { return m_tokenizer.get(); }
+ HTMLTreeBuilder* treeBuilder() const { return m_treeBuilder.get(); }
+
private:
// DocumentParser
virtual void detach();
virtual bool hasInsertionPoint();
- virtual void append(const SegmentedString&);
virtual bool finishWasCalled();
virtual bool processingData() const;
+ virtual void prepareToStopParsing();
virtual void stopParsing();
virtual bool isWaitingForScripts() const;
virtual bool isExecutingScript() const;
@@ -113,6 +117,7 @@ private:
void begin();
void attemptToEnd();
void endIfDelayed();
+ void attemptToRunDeferredScriptsAndEnd();
void end();
bool isScheduledForResume() const;
diff --git a/WebCore/html/HTMLInputStream.h b/WebCore/html/parser/HTMLInputStream.h
index a709bd9..a709bd9 100644
--- a/WebCore/html/HTMLInputStream.h
+++ b/WebCore/html/parser/HTMLInputStream.h
diff --git a/WebCore/html/parser/HTMLPreloadScanner.cpp b/WebCore/html/parser/HTMLPreloadScanner.cpp
index 7aafd90..5283fa3 100644
--- a/WebCore/html/parser/HTMLPreloadScanner.cpp
+++ b/WebCore/html/parser/HTMLPreloadScanner.cpp
@@ -29,7 +29,7 @@
#include "HTMLPreloadScanner.h"
#include "CSSHelper.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
#include "Document.h"
#include "HTMLTokenizer.h"
#include "HTMLTreeBuilder.h"
@@ -98,13 +98,13 @@ public:
if (m_urlToLoad.isEmpty())
return;
- DocLoader* docLoader = document->docLoader();
+ CachedResourceLoader* cachedResourceLoader = document->cachedResourceLoader();
if (m_tagName == scriptTag)
- docLoader->preload(CachedResource::Script, m_urlToLoad, m_charset, scanningBody);
+ cachedResourceLoader->preload(CachedResource::Script, m_urlToLoad, m_charset, scanningBody);
else if (m_tagName == imgTag)
- docLoader->preload(CachedResource::ImageResource, m_urlToLoad, String(), scanningBody);
+ cachedResourceLoader->preload(CachedResource::ImageResource, m_urlToLoad, String(), scanningBody);
else if (m_tagName == linkTag && m_linkIsStyleSheet)
- docLoader->preload(CachedResource::CSSStyleSheet, m_urlToLoad, m_charset, scanningBody);
+ cachedResourceLoader->preload(CachedResource::CSSStyleSheet, m_urlToLoad, m_charset, scanningBody);
}
const AtomicString& tagName() const { return m_tagName; }
diff --git a/WebCore/html/parser/HTMLScriptRunner.cpp b/WebCore/html/parser/HTMLScriptRunner.cpp
index 6d470a0..e1fc120 100644
--- a/WebCore/html/parser/HTMLScriptRunner.cpp
+++ b/WebCore/html/parser/HTMLScriptRunner.cpp
@@ -28,7 +28,7 @@
#include "Attribute.h"
#include "CachedScript.h"
-#include "DocLoader.h"
+#include "CachedResourceLoader.h"
#include "Element.h"
#include "Event.h"
#include "Frame.h"
@@ -75,6 +75,12 @@ HTMLScriptRunner::~HTMLScriptRunner()
// FIXME: Should we be passed a "done loading/parsing" callback sooner than destruction?
if (m_parsingBlockingScript.cachedScript() && m_parsingBlockingScript.watchingForLoad())
stopWatchingForLoad(m_parsingBlockingScript);
+
+ while (!m_scriptsToExecuteAfterParsing.isEmpty()) {
+ PendingScript pendingScript = m_scriptsToExecuteAfterParsing.takeFirst();
+ if (pendingScript.cachedScript() && pendingScript.watchingForLoad())
+ stopWatchingForLoad(pendingScript);
+ }
}
void HTMLScriptRunner::detach()
@@ -129,10 +135,6 @@ void HTMLScriptRunner::executeParsingBlockingScript()
ASSERT(m_document->haveStylesheetsLoaded());
ASSERT(isPendingScriptReady(m_parsingBlockingScript));
- // Stop watching loads before executeScript to prevent recursion if the script reloads itself.
- if (m_parsingBlockingScript.cachedScript() && m_parsingBlockingScript.watchingForLoad())
- stopWatchingForLoad(m_parsingBlockingScript);
-
InsertionPointRecord insertionPointRecord(m_host->inputStream());
executePendingScriptAndDispatchEvent(m_parsingBlockingScript);
}
@@ -142,6 +144,10 @@ void HTMLScriptRunner::executePendingScriptAndDispatchEvent(PendingScript& pendi
bool errorOccurred = false;
ScriptSourceCode sourceCode = sourceFromPendingScript(pendingScript, errorOccurred);
+ // Stop watching loads before executeScript to prevent recursion if the script reloads itself.
+ if (pendingScript.cachedScript() && pendingScript.watchingForLoad())
+ stopWatchingForLoad(pendingScript);
+
// Clear the pending script before possible rentrancy from executeScript()
RefPtr<Element> scriptElement = pendingScript.releaseElementAndClear();
{
@@ -238,6 +244,24 @@ bool HTMLScriptRunner::executeScriptsWaitingForStylesheets()
return executeParsingBlockingScripts();
}
+bool HTMLScriptRunner::executeScriptsWaitingForParsing()
+{
+ while (!m_scriptsToExecuteAfterParsing.isEmpty()) {
+ ASSERT(!m_scriptNestingLevel);
+ ASSERT(!haveParsingBlockingScript());
+ ASSERT(m_scriptsToExecuteAfterParsing.first().cachedScript());
+ if (!m_scriptsToExecuteAfterParsing.first().cachedScript()->isLoaded()) {
+ watchForLoad(m_scriptsToExecuteAfterParsing.first());
+ return false;
+ }
+ PendingScript first = m_scriptsToExecuteAfterParsing.takeFirst();
+ executePendingScriptAndDispatchEvent(first);
+ if (!m_document)
+ return false;
+ }
+ return true;
+}
+
void HTMLScriptRunner::requestParsingBlockingScript(Element* element)
{
if (!requestPendingScript(m_parsingBlockingScript, element))
@@ -252,6 +276,16 @@ void HTMLScriptRunner::requestParsingBlockingScript(Element* element)
watchForLoad(m_parsingBlockingScript);
}
+void HTMLScriptRunner::requestDeferredScript(Element* element)
+{
+ PendingScript pendingScript;
+ if (!requestPendingScript(pendingScript, element))
+ return;
+
+ ASSERT(pendingScript.cachedScript());
+ m_scriptsToExecuteAfterParsing.append(pendingScript);
+}
+
bool HTMLScriptRunner::requestPendingScript(PendingScript& pendingScript, Element* script) const
{
ASSERT(!pendingScript.element());
@@ -264,7 +298,7 @@ bool HTMLScriptRunner::requestPendingScript(PendingScript& pendingScript, Elemen
return false;
pendingScript.adoptElement(script);
// This should correctly return 0 for empty or invalid srcValues.
- CachedScript* cachedScript = m_document->docLoader()->requestScript(srcValue, toScriptElement(script)->scriptCharset());
+ CachedScript* cachedScript = m_document->cachedResourceLoader()->requestScript(srcValue, toScriptElement(script)->scriptCharset());
if (!cachedScript) {
notImplemented(); // Dispatch error event.
return false;
@@ -287,8 +321,13 @@ void HTMLScriptRunner::runScript(Element* script, int startingLineNumber)
notImplemented(); // event for support
if (script->hasAttribute(srcAttr)) {
- // FIXME: Handle defer and async
- requestParsingBlockingScript(script);
+ if (script->hasAttribute(asyncAttr)) // Async takes precendence over defer.
+ return; // Asynchronous scripts handle themselves.
+
+ if (script->hasAttribute(deferAttr))
+ requestDeferredScript(script);
+ else
+ requestParsingBlockingScript(script);
} else {
// FIXME: We do not block inline <script> tags on stylesheets to match the
// old parser for now. When we do, the ASSERT below should be added.
diff --git a/WebCore/html/parser/HTMLScriptRunner.h b/WebCore/html/parser/HTMLScriptRunner.h
index ead9289..47c96fd 100644
--- a/WebCore/html/parser/HTMLScriptRunner.h
+++ b/WebCore/html/parser/HTMLScriptRunner.h
@@ -27,6 +27,7 @@
#define HTMLScriptRunner_h
#include "PendingScript.h"
+#include <wtf/Deque.h>
#include <wtf/Noncopyable.h>
#include <wtf/PassRefPtr.h>
@@ -56,6 +57,7 @@ public:
bool executeScriptsWaitingForLoad(CachedResource*);
bool hasScriptsWaitingForStylesheets() const { return m_hasScriptsWaitingForStylesheets; }
bool executeScriptsWaitingForStylesheets();
+ bool executeScriptsWaitingForParsing();
bool isExecutingScript() const { return !!m_scriptNestingLevel; }
@@ -71,6 +73,7 @@ private:
bool executeParsingBlockingScripts();
void requestParsingBlockingScript(Element*);
+ void requestDeferredScript(Element*);
bool requestPendingScript(PendingScript&, Element*) const;
void runScript(Element*, int startingLineNumber);
@@ -84,6 +87,7 @@ private:
Document* m_document;
HTMLScriptRunnerHost* m_host;
PendingScript m_parsingBlockingScript;
+ Deque<PendingScript> m_scriptsToExecuteAfterParsing; // http://www.whatwg.org/specs/web-apps/current-work/#list-of-scripts-that-will-execute-when-the-document-has-finished-parsing
unsigned m_scriptNestingLevel;
// We only want stylesheet loads to trigger script execution if script
diff --git a/WebCore/html/parser/HTMLTokenizer.cpp b/WebCore/html/parser/HTMLTokenizer.cpp
index 5791842..f5405ff 100644
--- a/WebCore/html/parser/HTMLTokenizer.cpp
+++ b/WebCore/html/parser/HTMLTokenizer.cpp
@@ -293,7 +293,9 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
ADVANCE_TO(DataState);
if (m_state == RCDATAState)
ADVANCE_TO(RCDATAState);
- ASSERT_NOT_REACHED();
+ // When parsing text/plain documents, we run the tokenizer in the
+ // PLAINTEXTState and ignore m_skipLeadingNewLineForListing.
+ ASSERT(m_state == PLAINTEXTState);
}
}
diff --git a/WebCore/html/parser/HTMLTreeBuilder.cpp b/WebCore/html/parser/HTMLTreeBuilder.cpp
index 8c76fc0..406bb6c 100644
--- a/WebCore/html/parser/HTMLTreeBuilder.cpp
+++ b/WebCore/html/parser/HTMLTreeBuilder.cpp
@@ -463,6 +463,11 @@ HTMLTokenizer::State HTMLTreeBuilder::adjustedLexerState(HTMLTokenizer::State st
void HTMLTreeBuilder::constructTreeFromToken(HTMLToken& rawToken)
{
AtomicHTMLToken token(rawToken);
+ constructTreeFromAtomicToken(token);
+}
+
+void HTMLTreeBuilder::constructTreeFromAtomicToken(AtomicHTMLToken& token)
+{
processToken(token);
// Swallowing U+0000 characters isn't in the HTML5 spec, but turning all
diff --git a/WebCore/html/parser/HTMLTreeBuilder.h b/WebCore/html/parser/HTMLTreeBuilder.h
index c30e6b8..4634f0a 100644
--- a/WebCore/html/parser/HTMLTreeBuilder.h
+++ b/WebCore/html/parser/HTMLTreeBuilder.h
@@ -68,6 +68,8 @@ public:
// The token really should be passed as a const& since it's never modified.
void constructTreeFromToken(HTMLToken&);
+ void constructTreeFromAtomicToken(AtomicHTMLToken&);
+
// Must be called when parser is paused before calling the parser again.
PassRefPtr<Element> takeScriptToProcess(int& scriptStartLine);
diff --git a/WebCore/html/parser/HTMLViewSourceParser.h b/WebCore/html/parser/HTMLViewSourceParser.h
index 34caf43..abe55b4 100644
--- a/WebCore/html/parser/HTMLViewSourceParser.h
+++ b/WebCore/html/parser/HTMLViewSourceParser.h
@@ -50,9 +50,12 @@ public:
}
virtual ~HTMLViewSourceParser();
-private:
- HTMLViewSourceParser(HTMLViewSourceDocument*);
+protected:
+ explicit HTMLViewSourceParser(HTMLViewSourceDocument*);
+
+ HTMLTokenizer* tokenizer() const { return m_tokenizer.get(); }
+private:
// DocumentParser
virtual void insert(const SegmentedString&);
virtual void append(const SegmentedString&);
diff --git a/WebCore/html/parser/TextDocumentParser.cpp b/WebCore/html/parser/TextDocumentParser.cpp
new file mode 100644
index 0000000..d03b744
--- /dev/null
+++ b/WebCore/html/parser/TextDocumentParser.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TextDocumentParser.h"
+
+#include "HTMLDocument.h"
+#include "HTMLNames.h"
+#include "HTMLTokenizer.h"
+#include "HTMLTreeBuilder.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+TextDocumentParser::TextDocumentParser(HTMLDocument* document)
+ : HTMLDocumentParser(document, false)
+ , m_haveInsertedFakePreElement(false)
+{
+ tokenizer()->setState(HTMLTokenizer::PLAINTEXTState);
+}
+
+TextDocumentParser::~TextDocumentParser()
+{
+}
+
+void TextDocumentParser::append(const SegmentedString& text)
+{
+ if (!m_haveInsertedFakePreElement)
+ insertFakePreElement();
+ HTMLDocumentParser::append(text);
+}
+
+void TextDocumentParser::insertFakePreElement()
+{
+ // In principle, we should create a specialized tree builder for
+ // TextDocuments, but instead we re-use the existing HTMLTreeBuilder.
+ // We create a fake token and give it to the tree builder rather than
+ // sending fake bytes through the front-end of the parser to avoid
+ // distrubing the line/column number calculations.
+
+ RefPtr<Attribute> styleAttribute = Attribute::createMapped("style", "word-wrap: break-word; white-space: pre-wrap;");
+ RefPtr<NamedNodeMap> attributes = NamedNodeMap::create();
+ attributes->insertAttribute(styleAttribute.release(), false);
+ AtomicHTMLToken fakePre(HTMLToken::StartTag, preTag.localName(), attributes.release());
+
+ treeBuilder()->constructTreeFromAtomicToken(fakePre);
+ m_haveInsertedFakePreElement = true;
+}
+
+}
diff --git a/WebCore/html/parser/TextDocumentParser.h b/WebCore/html/parser/TextDocumentParser.h
new file mode 100644
index 0000000..1cccc5b
--- /dev/null
+++ b/WebCore/html/parser/TextDocumentParser.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef TextDocumentParser_h
+#define TextDocumentParser_h
+
+#include "HTMLDocumentParser.h"
+
+namespace WebCore {
+
+class TextDocumentParser : public HTMLDocumentParser {
+public:
+ static PassRefPtr<TextDocumentParser> create(HTMLDocument* document)
+ {
+ return adoptRef(new TextDocumentParser(document));
+ }
+ virtual ~TextDocumentParser();
+
+private:
+ explicit TextDocumentParser(HTMLDocument*);
+
+ virtual void append(const SegmentedString&);
+ void insertFakePreElement();
+
+ bool m_haveInsertedFakePreElement;
+};
+
+}
+
+#endif
diff --git a/WebCore/html/parser/TextViewSourceParser.cpp b/WebCore/html/parser/TextViewSourceParser.cpp
new file mode 100644
index 0000000..d7e6e3d
--- /dev/null
+++ b/WebCore/html/parser/TextViewSourceParser.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TextViewSourceParser.h"
+
+#include "HTMLTokenizer.h"
+
+namespace WebCore {
+
+TextViewSourceParser::TextViewSourceParser(HTMLViewSourceDocument* document)
+ : HTMLViewSourceParser(document)
+{
+ tokenizer()->setState(HTMLTokenizer::PLAINTEXTState);
+}
+
+TextViewSourceParser::~TextViewSourceParser()
+{
+}
+
+}
diff --git a/WebCore/html/parser/TextViewSourceParser.h b/WebCore/html/parser/TextViewSourceParser.h
new file mode 100644
index 0000000..e4170ed
--- /dev/null
+++ b/WebCore/html/parser/TextViewSourceParser.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010 Google, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TextViewSourceParser_h
+#define TextViewSourceParser_h
+
+#include "HTMLViewSourceParser.h"
+
+namespace WebCore {
+
+class TextViewSourceParser : public HTMLViewSourceParser {
+public:
+ static PassRefPtr<TextViewSourceParser> create(HTMLViewSourceDocument* document)
+ {
+ return adoptRef(new TextViewSourceParser(document));
+ }
+ virtual ~TextViewSourceParser();
+
+private:
+ explicit TextViewSourceParser(HTMLViewSourceDocument*);
+};
+
+}
+
+#endif