summaryrefslogtreecommitdiffstats
path: root/WebCore/html
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/html')
-rw-r--r--WebCore/html/Blob.cpp73
-rw-r--r--WebCore/html/Blob.h36
-rw-r--r--WebCore/html/BlobBuilder.cpp2
-rw-r--r--WebCore/html/BlobURL.cpp66
-rw-r--r--WebCore/html/BlobURL.h48
-rw-r--r--WebCore/html/DataGridColumn.h2
-rw-r--r--WebCore/html/DataGridColumnList.cpp2
-rw-r--r--WebCore/html/File.cpp12
-rw-r--r--WebCore/html/File.h12
-rw-r--r--WebCore/html/FileReader.cpp63
-rw-r--r--WebCore/html/FileReader.h13
-rw-r--r--WebCore/html/FileReader.idl3
-rw-r--r--WebCore/html/FileStream.cpp138
-rw-r--r--WebCore/html/FileStream.h45
-rw-r--r--WebCore/html/FileStreamClient.h10
-rw-r--r--WebCore/html/FileStreamProxy.cpp140
-rw-r--r--WebCore/html/FileStreamProxy.h31
-rw-r--r--WebCore/html/FileThreadTask.h50
-rw-r--r--WebCore/html/HTMLAnchorElement.cpp4
-rw-r--r--WebCore/html/HTMLCanvasElement.cpp39
-rw-r--r--WebCore/html/HTMLCanvasElement.h5
-rw-r--r--WebCore/html/HTMLConstructionSite.cpp9
-rw-r--r--WebCore/html/HTMLDocument.cpp9
-rw-r--r--WebCore/html/HTMLDocument.h2
-rw-r--r--WebCore/html/HTMLDocumentParser.h6
-rw-r--r--WebCore/html/HTMLElement.cpp94
-rw-r--r--WebCore/html/HTMLElement.h3
-rw-r--r--WebCore/html/HTMLEmbedElement.cpp4
-rw-r--r--WebCore/html/HTMLEntityNames.gperf303
-rw-r--r--WebCore/html/HTMLEntityParser.cpp109
-rw-r--r--WebCore/html/HTMLEntityParser.h3
-rw-r--r--WebCore/html/HTMLEntitySearch.cpp132
-rw-r--r--WebCore/html/HTMLEntitySearch.h (renamed from WebCore/html/canvas/CanvasNumberArray.h)69
-rw-r--r--WebCore/html/HTMLEntityTable.h (renamed from WebCore/html/canvas/CanvasNumberArray.cpp)39
-rw-r--r--WebCore/html/HTMLFormControlElement.cpp4
-rw-r--r--WebCore/html/HTMLInputElement.cpp2
-rw-r--r--WebCore/html/HTMLInputElement.h1
-rw-r--r--WebCore/html/HTMLLinkElement.cpp29
-rw-r--r--WebCore/html/HTMLLinkElement.h4
-rw-r--r--WebCore/html/HTMLMediaElement.cpp25
-rw-r--r--WebCore/html/HTMLMediaElement.h1
-rw-r--r--WebCore/html/HTMLObjectElement.cpp4
-rw-r--r--WebCore/html/HTMLScriptRunner.cpp84
-rw-r--r--WebCore/html/HTMLScriptRunner.h14
-rw-r--r--WebCore/html/HTMLSourceElement.cpp4
-rw-r--r--WebCore/html/HTMLSourceElement.h2
-rw-r--r--WebCore/html/HTMLToken.h60
-rw-r--r--WebCore/html/HTMLTokenizer.cpp85
-rw-r--r--WebCore/html/HTMLTokenizer.h4
-rw-r--r--WebCore/html/HTMLTreeBuilder.cpp67
-rw-r--r--WebCore/html/HTMLViewSourceDocument.cpp195
-rw-r--r--WebCore/html/HTMLViewSourceDocument.h17
-rw-r--r--WebCore/html/HTMLViewSourceParser.cpp106
-rw-r--r--WebCore/html/HTMLViewSourceParser.h77
-rw-r--r--WebCore/html/LegacyHTMLDocumentParser.cpp2126
-rw-r--r--WebCore/html/LegacyHTMLDocumentParser.h452
-rw-r--r--WebCore/html/LegacyHTMLTreeBuilder.cpp2
-rw-r--r--WebCore/html/LegacyHTMLTreeBuilder.h93
-rw-r--r--WebCore/html/LegacyPreloadScanner.cpp856
-rw-r--r--WebCore/html/LegacyPreloadScanner.h144
-rw-r--r--WebCore/html/ThreadableBlobRegistry.cpp96
-rw-r--r--WebCore/html/ThreadableBlobRegistry.h51
-rw-r--r--WebCore/html/canvas/CanvasNumberArray.idl33
-rw-r--r--WebCore/html/canvas/CanvasPattern.cpp2
-rw-r--r--WebCore/html/canvas/CanvasPattern.h4
-rw-r--r--WebCore/html/canvas/CanvasRenderingContext2D.cpp60
-rw-r--r--WebCore/html/canvas/CanvasStyle.cpp18
-rw-r--r--WebCore/html/canvas/CanvasStyle.h22
-rw-r--r--WebCore/html/canvas/WebGLObject.cpp20
-rw-r--r--WebCore/html/canvas/WebGLObject.h21
-rw-r--r--WebCore/html/canvas/WebGLProgram.cpp62
-rw-r--r--WebCore/html/canvas/WebGLProgram.h9
-rw-r--r--WebCore/html/canvas/WebGLRenderingContext.cpp418
-rw-r--r--WebCore/html/canvas/WebGLRenderingContext.h38
-rw-r--r--WebCore/html/canvas/WebGLRenderingContext.idl18
-rw-r--r--WebCore/html/canvas/WebGLTexture.cpp27
76 files changed, 1923 insertions, 5010 deletions
diff --git a/WebCore/html/Blob.cpp b/WebCore/html/Blob.cpp
index 977ffa6..3a62ab1 100644
--- a/WebCore/html/Blob.cpp
+++ b/WebCore/html/Blob.cpp
@@ -31,29 +31,93 @@
#include "config.h"
#include "Blob.h"
+#include "BlobData.h"
#include "BlobItem.h"
+#include "BlobURL.h"
#include "FileSystem.h"
+#include "ScriptExecutionContext.h"
+#include "ThreadableBlobRegistry.h"
namespace WebCore {
-Blob::Blob(ScriptExecutionContext*, const String& type, const BlobItemList& items)
- : m_type(type)
+// FIXME: To be removed when we switch to using BlobData.
+Blob::Blob(ScriptExecutionContext* scriptExecutionContext, const String& type, const BlobItemList& items)
+ : m_scriptExecutionContext(scriptExecutionContext)
+ , m_type(type)
+ , m_size(0)
{
+ m_scriptExecutionContext->addBlob(this);
for (size_t i = 0; i < items.size(); ++i)
m_items.append(items[i]);
}
-Blob::Blob(ScriptExecutionContext*, const PassRefPtr<BlobItem>& item)
+// FIXME: To be removed when we switch to using BlobData.
+Blob::Blob(ScriptExecutionContext* scriptExecutionContext, const PassRefPtr<BlobItem>& item)
+ : m_scriptExecutionContext(scriptExecutionContext)
+ , m_size(0)
{
+ m_scriptExecutionContext->addBlob(this);
m_items.append(item);
}
-Blob::Blob(ScriptExecutionContext*, const String& path)
+// FIXME: To be removed when we switch to using BlobData.
+Blob::Blob(ScriptExecutionContext* scriptExecutionContext, const String& path)
+ : m_scriptExecutionContext(scriptExecutionContext)
+ , m_size(0)
{
+ m_scriptExecutionContext->addBlob(this);
// Note: this doesn't initialize the type unlike File(path).
m_items.append(FileBlobItem::create(path));
}
+Blob::Blob(ScriptExecutionContext* scriptExecutionContext, PassOwnPtr<BlobData> blobData, long long size)
+ : m_scriptExecutionContext(scriptExecutionContext)
+ , m_type(blobData->contentType())
+ , m_size(size)
+{
+ ASSERT(blobData.get() && !blobData->items().isEmpty());
+
+ m_scriptExecutionContext->addBlob(this);
+
+ // Create a new internal URL and register it with the provided blob data.
+ m_url = BlobURL::createURL(scriptExecutionContext);
+ ThreadableBlobRegistry::registerBlobURL(scriptExecutionContext, m_url, blobData);
+}
+
+Blob::Blob(ScriptExecutionContext* scriptExecutionContext, const KURL& srcURL, const String& type, long long size)
+ : m_scriptExecutionContext(scriptExecutionContext)
+ , m_type(type)
+ , m_size(size)
+{
+ m_scriptExecutionContext->addBlob(this);
+
+ // FIXME: To be removed when we switch to using BlobData.
+ if (srcURL.isEmpty())
+ return;
+
+ // Create a new internal URL and register it with the same blob data as the source URL.
+ m_url = BlobURL::createURL(scriptExecutionContext);
+ ThreadableBlobRegistry::registerBlobURL(scriptExecutionContext, m_url, srcURL);
+}
+
+Blob::~Blob()
+{
+ // The internal URL is only used to refer to the Blob object. So we need to unregister the URL when the object is GC-ed.
+ if (m_scriptExecutionContext) {
+ m_scriptExecutionContext->removeBlob(this);
+ ThreadableBlobRegistry::unregisterBlobURL(m_scriptExecutionContext, m_url);
+ }
+}
+
+void Blob::contextDestroyed()
+{
+ ASSERT(m_scriptExecutionContext);
+
+ // Unregister the internal URL before the context is gone.
+ ThreadableBlobRegistry::unregisterBlobURL(m_scriptExecutionContext, m_url);
+ m_scriptExecutionContext = 0;
+}
+
unsigned long long Blob::size() const
{
// FIXME: JavaScript cannot represent sizes as large as unsigned long long, we need to
@@ -64,6 +128,7 @@ unsigned long long Blob::size() const
return size;
}
+// FIXME: To be removed when we switch to using BlobData.
const String& Blob::path() const
{
ASSERT(m_items.size() == 1 && m_items[0]->toFileBlobItem());
diff --git a/WebCore/html/Blob.h b/WebCore/html/Blob.h
index 7afc7a0..374a401 100644
--- a/WebCore/html/Blob.h
+++ b/WebCore/html/Blob.h
@@ -32,39 +32,45 @@
#define Blob_h
#include "BlobItem.h"
+#include "KURL.h"
#include "PlatformString.h"
+#include <wtf/PassOwnPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/Vector.h>
namespace WebCore {
+class BlobData;
class ScriptExecutionContext;
class Blob : public RefCounted<Blob> {
public:
+ // FIXME: To be removed when we switch to using BlobData.
static PassRefPtr<Blob> create(ScriptExecutionContext* scriptExecutionContext, const String& type, const BlobItemList& items)
{
return adoptRef(new Blob(scriptExecutionContext, type, items));
}
- // FIXME: Deprecated method. This is called only from
- // bindings/v8/SerializedScriptValue.cpp and the usage in it will become invalid once
- // BlobBuilder is introduced.
- static PassRefPtr<Blob> create(ScriptExecutionContext* scriptExecutionContext, const String& path)
+ // For deserialization.
+ static PassRefPtr<Blob> create(ScriptExecutionContext* scriptExecutionContext, const KURL& srcURL, const String& type, long long size)
{
- return adoptRef(new Blob(scriptExecutionContext, path));
+ return adoptRef(new Blob(scriptExecutionContext, srcURL, type, size));
}
- virtual ~Blob() { }
+ virtual ~Blob();
+ void contextDestroyed();
+
+ const KURL& url() const { return m_url; }
unsigned long long size() const;
const String& type() const { return m_type; }
virtual bool isFile() const { return false; }
- // FIXME: Deprecated method.
+ // FIXME: To be removed when we switch to using BlobData.
const String& path() const;
+ // FIXME: To be removed when we switch to using BlobData.
const BlobItemList& items() const { return m_items; }
#if ENABLE(BLOB)
@@ -72,14 +78,26 @@ public:
#endif
protected:
+ // FIXME: To be removed when we switch to using BlobData.
Blob(ScriptExecutionContext*, const String& type, const BlobItemList&);
Blob(ScriptExecutionContext*, const PassRefPtr<BlobItem>&);
-
- // FIXME: Deprecated constructor. See also the comment for Blob::create(path).
Blob(ScriptExecutionContext*, const String& path);
+ Blob(ScriptExecutionContext*, PassOwnPtr<BlobData>, long long size);
+
+ // For deserialization.
+ Blob(ScriptExecutionContext*, const KURL& srcURL, const String& type, long long size);
+
+ // FIXME: To be removed when we switch to using BlobData.
BlobItemList m_items;
+
+ // This is an internal URL referring to the blob data associated with this object.
+ // It is only used by FileReader to read the blob data via loading from the blob URL resource.
+ KURL m_url;
+
+ ScriptExecutionContext* m_scriptExecutionContext;
String m_type;
+ long long m_size;
};
} // namespace WebCore
diff --git a/WebCore/html/BlobBuilder.cpp b/WebCore/html/BlobBuilder.cpp
index 0592ff0..29a7595 100644
--- a/WebCore/html/BlobBuilder.cpp
+++ b/WebCore/html/BlobBuilder.cpp
@@ -32,11 +32,11 @@
#include "BlobBuilder.h"
-#include "AtomicString.h"
#include "Blob.h"
#include "ExceptionCode.h"
#include "LineEnding.h"
#include "TextEncoding.h"
+#include <wtf/text/AtomicString.h>
namespace WebCore {
diff --git a/WebCore/html/BlobURL.cpp b/WebCore/html/BlobURL.cpp
new file mode 100644
index 0000000..610aac4
--- /dev/null
+++ b/WebCore/html/BlobURL.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 "BlobURL.h"
+
+#include "KURL.h"
+#include "PlatformString.h"
+#include "ScriptExecutionContext.h"
+#include "SecurityOrigin.h"
+#include "UUID.h"
+
+namespace WebCore {
+
+KURL BlobURL::createURL(ScriptExecutionContext* scriptExecutionContext)
+{
+ // Create the blob URL in the following format:
+ // blob:%escaped_origin%/%UUID%
+ // The origin of the host page is encoded in the URL value to allow easy lookup of the origin when the security check needs
+ // to be performed.
+ String urlString = "blob:";
+ urlString += encodeWithURLEscapeSequences(scriptExecutionContext->securityOrigin()->toString());
+ urlString += "/";
+ urlString += createCanonicalUUIDString();
+ return KURL(ParsedURLString, urlString);
+}
+
+KURL BlobURL::getOrigin(const KURL& url)
+{
+ ASSERT(url.protocolIs("blob"));
+
+ unsigned startIndex = url.pathStart();
+ unsigned afterEndIndex = url.pathAfterLastSlash();
+ String origin = url.string().substring(startIndex, afterEndIndex - startIndex);
+ return KURL(ParsedURLString, decodeURLEscapeSequences(origin));
+}
+
+} // namespace WebCore
diff --git a/WebCore/html/BlobURL.h b/WebCore/html/BlobURL.h
new file mode 100644
index 0000000..2ce2c85
--- /dev/null
+++ b/WebCore/html/BlobURL.h
@@ -0,0 +1,48 @@
+/*
+ * 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 BlobURL_h
+#define BlobURL_h
+
+#include "KURL.h"
+
+namespace WebCore {
+
+class ScriptExecutionContext;
+
+class BlobURL {
+public:
+ static KURL createURL(ScriptExecutionContext*);
+ static KURL getOrigin(const KURL&);
+};
+
+}
+
+#endif // BlobURL_h
diff --git a/WebCore/html/DataGridColumn.h b/WebCore/html/DataGridColumn.h
index 3d480a9..555389c 100644
--- a/WebCore/html/DataGridColumn.h
+++ b/WebCore/html/DataGridColumn.h
@@ -28,10 +28,10 @@
#if ENABLE(DATAGRID)
-#include "AtomicString.h"
#include "RenderStyle.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
+#include <wtf/text/AtomicString.h>
namespace WebCore {
diff --git a/WebCore/html/DataGridColumnList.cpp b/WebCore/html/DataGridColumnList.cpp
index 9613402..15590b2 100644
--- a/WebCore/html/DataGridColumnList.cpp
+++ b/WebCore/html/DataGridColumnList.cpp
@@ -27,11 +27,11 @@
#if ENABLE(DATAGRID)
-#include "AtomicString.h"
#include "DataGridColumnList.h"
#include "HTMLDataGridElement.h"
#include "PlatformString.h"
#include "RenderObject.h"
+#include <wtf/text/AtomicString.h>
namespace WebCore {
diff --git a/WebCore/html/File.cpp b/WebCore/html/File.cpp
index 109e0d3..253cb4d 100644
--- a/WebCore/html/File.cpp
+++ b/WebCore/html/File.cpp
@@ -26,6 +26,7 @@
#include "config.h"
#include "File.h"
+#include "BlobData.h"
#include "FileSystem.h"
#include "MIMETypeRegistry.h"
@@ -37,6 +38,13 @@ File::File(ScriptExecutionContext* scriptExecutionContext, const String& path)
Init();
}
+File::File(ScriptExecutionContext* scriptExecutionContext, const String& path, const KURL& url, const String& type)
+ : Blob(scriptExecutionContext, url, type, BlobDataItem::toEndOfFile)
+{
+ // FIXME: To be removed when we switch to using BlobData.
+ m_items.append(FileBlobItem::create(path));
+}
+
#if ENABLE(DIRECTORY_UPLOAD)
File::File(ScriptExecutionContext* scriptExecutionContext, const String& relativePath, const String& filePath)
: Blob(scriptExecutionContext, FileBlobItem::create(filePath, relativePath))
@@ -49,8 +57,8 @@ void File::Init()
{
// We don't use MIMETypeRegistry::getMIMETypeForPath() because it returns "application/octet-stream" upon failure.
const String& fileName = name();
- int index = fileName.reverseFind('.');
- if (index != -1)
+ size_t index = fileName.reverseFind('.');
+ if (index != notFound)
m_type = MIMETypeRegistry::getMIMETypeForExtension(fileName.substring(index + 1));
}
diff --git a/WebCore/html/File.h b/WebCore/html/File.h
index c0aecc8..06a73c5 100644
--- a/WebCore/html/File.h
+++ b/WebCore/html/File.h
@@ -39,6 +39,12 @@ public:
return adoptRef(new File(scriptExecutionContext, path));
}
+ // For deserialization.
+ static PassRefPtr<File> create(ScriptExecutionContext* scriptExecutionContext, const String& path, const KURL& url, const String& type)
+ {
+ return adoptRef(new File(scriptExecutionContext, path, url, type));
+ }
+
#if ENABLE(DIRECTORY_UPLOAD)
static PassRefPtr<File> create(ScriptExecutionContext* scriptExecutionContext, const String& relativePath, const String& path)
{
@@ -60,11 +66,15 @@ public:
private:
File(ScriptExecutionContext*, const String& path);
- void Init();
+
+ // For deserialization.
+ File(ScriptExecutionContext*, const String& path, const KURL&, const String& type);
#if ENABLE(DIRECTORY_UPLOAD)
File(ScriptExecutionContext*, const String& relativePath, const String& path);
#endif
+
+ void Init();
};
} // namespace WebCore
diff --git a/WebCore/html/FileReader.cpp b/WebCore/html/FileReader.cpp
index 88f218f..e99fdc4 100644
--- a/WebCore/html/FileReader.cpp
+++ b/WebCore/html/FileReader.cpp
@@ -160,33 +160,70 @@ void FileReader::terminate()
void FileReader::didStart()
{
m_state = Opening;
- m_streamProxy->openForRead(m_fileBlob.get());
+
+ ASSERT(m_fileBlob->items().size() == 1 && m_fileBlob->items().at(0)->toFileBlobItem());
+ const FileRangeBlobItem* fileRangeItem = m_fileBlob->items().at(0)->toFileRangeBlobItem();
+ double expectedModificationTime = fileRangeItem ? fileRangeItem->snapshotModificationTime() : 0;
+
+ m_streamProxy->getSize(m_fileBlob->path(), expectedModificationTime);
}
void FileReader::didGetSize(long long size)
{
+ // If the size is -1, it means the file has been moved or changed. Fail now.
+ if (size == -1) {
+ didFail(NOT_FOUND_ERR);
+ return;
+ }
+
m_state = Reading;
fireEvent(eventNames().loadstartEvent);
- m_totalBytes = size;
- m_streamProxy->read(&m_buffer.at(0), m_buffer.size());
+ ASSERT(m_fileBlob->items().size() == 1 && m_fileBlob->items().at(0)->toFileBlobItem());
+ const FileRangeBlobItem* fileRangeItem = m_fileBlob->items().at(0)->toFileRangeBlobItem();
+ long long start = fileRangeItem ? fileRangeItem->start() : 0;
+
+ // The size passed back is the size of the whole file. If the underlying item is a sliced file, we need to use the slice length.
+ m_totalBytes = fileRangeItem ? fileRangeItem->size() : size;
+
+ m_streamProxy->openForRead(m_fileBlob->path(), start, m_totalBytes);
}
-void FileReader::didRead(const char* data, int bytesRead)
+void FileReader::didOpen(ExceptionCode ec)
{
- ASSERT(data && bytesRead);
+ if (ec) {
+ didFail(ec);
+ return;
+ }
+
+ m_streamProxy->read(m_buffer.data(), m_buffer.size());
+}
+void FileReader::didRead(int bytesRead)
+{
// Bail out if we have aborted the reading.
if (m_state == Completed)
- return;
+ return;
+
+ // If bytesRead is -1, it means an error happens.
+ if (bytesRead == -1) {
+ didFail(NOT_READABLE_ERR);
+ return;
+ }
+
+ // If bytesRead is 0, it means the reading is done.
+ if (!bytesRead) {
+ didFinish();
+ return;
+ }
switch (m_readType) {
case ReadFileAsBinaryString:
- m_result += String(data, static_cast<unsigned>(bytesRead));
+ m_result += String(m_buffer.data(), static_cast<unsigned>(bytesRead));
break;
case ReadFileAsText:
case ReadFileAsDataURL:
- m_rawData.append(data, static_cast<unsigned>(bytesRead));
+ m_rawData.append(m_buffer.data(), static_cast<unsigned>(bytesRead));
m_isRawDataConverted = false;
break;
default:
@@ -205,7 +242,7 @@ void FileReader::didRead(const char* data, int bytesRead)
}
// Continue reading.
- m_streamProxy->read(&m_buffer.at(0), m_buffer.size());
+ m_streamProxy->read(m_buffer.data(), m_buffer.size());
}
void FileReader::didFinish()
@@ -240,15 +277,15 @@ FileReader::ReadyState FileReader::readyState() const
switch (m_state) {
case None:
case Starting:
- return Empty;
+ return EMPTY;
case Opening:
case Reading:
- return Loading;
+ return LOADING;
case Completed:
- return Done;
+ return DONE;
}
ASSERT_NOT_REACHED();
- return Empty;
+ return EMPTY;
}
const ScriptString& FileReader::result()
diff --git a/WebCore/html/FileReader.h b/WebCore/html/FileReader.h
index a5339a9..2237af5 100644
--- a/WebCore/html/FileReader.h
+++ b/WebCore/html/FileReader.h
@@ -63,9 +63,9 @@ public:
virtual ~FileReader();
enum ReadyState {
- Empty = 0,
- Loading = 1,
- Done = 2
+ EMPTY = 0,
+ LOADING = 1,
+ DONE = 2
};
void readAsBinaryString(Blob*);
@@ -89,9 +89,8 @@ public:
// FileStreamClient
virtual void didStart();
virtual void didGetSize(long long);
- virtual void didRead(const char*, int);
- virtual void didFinish();
- virtual void didFail(ExceptionCode);
+ virtual void didOpen(ExceptionCode);
+ virtual void didRead(int);
using RefCounted<FileReader>::ref;
using RefCounted<FileReader>::deref;
@@ -130,6 +129,8 @@ private:
void fireEvent(const AtomicString& type);
void convertToText();
void convertToDataURL();
+ void didFinish();
+ void didFail(ExceptionCode);
InternalState m_state;
EventTargetData m_eventTargetData;
diff --git a/WebCore/html/FileReader.idl b/WebCore/html/FileReader.idl
index fb3b979..b36e9d3 100644
--- a/WebCore/html/FileReader.idl
+++ b/WebCore/html/FileReader.idl
@@ -34,8 +34,7 @@ module html {
CanBeConstructed,
CallWith=ScriptExecutionContext,
EventTarget,
- NoStaticTables,
- DontCheckEnums
+ NoStaticTables
] FileReader {
// ready states
const unsigned short EMPTY = 0;
diff --git a/WebCore/html/FileStream.cpp b/WebCore/html/FileStream.cpp
index abe7bad..a89c67a 100644
--- a/WebCore/html/FileStream.cpp
+++ b/WebCore/html/FileStream.cpp
@@ -39,9 +39,8 @@
namespace WebCore {
-FileStream::FileStream(FileStreamClient* client)
- : m_client(client)
- , m_handle(invalidPlatformFileHandle)
+FileStream::FileStream()
+ : m_handle(invalidPlatformFileHandle)
, m_bytesProcessed(0)
, m_totalBytesToRead(0)
{
@@ -52,130 +51,99 @@ FileStream::~FileStream()
ASSERT(!isHandleValid(m_handle));
}
+// FIXME: To be removed when we switch to using BlobData.
void FileStream::start()
{
- ASSERT(!isMainThread());
- m_client->didStart();
}
void FileStream::stop()
{
- ASSERT(!isMainThread());
close();
- m_client->didStop();
}
-void FileStream::openForRead(Blob* blob)
+long long FileStream::getSize(const String& path, double expectedModificationTime)
{
- ASSERT(!isMainThread());
+ // Check the modification time for the possible file change.
+ time_t modificationTime;
+ if (!getFileModificationTime(path, modificationTime))
+ return -1;
+ if (expectedModificationTime) {
+ if (static_cast<time_t>(expectedModificationTime) != modificationTime)
+ return -1;
+ }
+
+ // Now get the file size.
+ long long length;
+ if (!getFileSize(path, length))
+ return -1;
+
+ return length;
+}
+ExceptionCode FileStream::openForRead(const String& path, long long offset, long long length)
+{
if (isHandleValid(m_handle))
- return;
-
- // FIXME: Need to handle multiple items that may include non-file ones when BlobBuilder is introduced.
- ASSERT(blob->items().size() >= 1);
- const FileBlobItem* fileItem = blob->items().at(0)->toFileBlobItem();
- if (!fileItem) {
- ASSERT(false);
- m_client->didFail(NOT_READABLE_ERR);
- return;
- }
+ return 0;
- // Check if the file exists by querying its modification time. We choose not to call fileExists() in order to save an
- // extra file system call when the modification time is needed to check the validity of the sliced file blob.
- // Per the spec, we need to return different error codes to differentiate between non-existent file and permission error.
- // openFile() could not tell use the failure reason.
- time_t currentModificationTime;
- if (!getFileModificationTime(fileItem->path(), currentModificationTime)) {
- m_client->didFail(NOT_FOUND_ERR);
- return;
- }
+ // Open the file.
+ m_handle = openFile(path, OpenForRead);
+ if (!isHandleValid(m_handle))
+ return NOT_READABLE_ERR;
- // Open the file blob.
- m_handle = openFile(fileItem->path(), OpenForRead);
- if (!isHandleValid(m_handle)) {
- m_client->didFail(NOT_READABLE_ERR);
- return;
+ // Jump to the beginning position if the file has been sliced.
+ if (offset > 0) {
+ if (seekFile(m_handle, offset, SeekFromBeginning) < 0)
+ return NOT_READABLE_ERR;
}
- const FileRangeBlobItem* fileRangeItem = fileItem->toFileRangeBlobItem();
- if (fileRangeItem) {
- // Check the modificationt time for the possible file change.
- if (static_cast<time_t>(fileRangeItem->snapshotModificationTime()) != currentModificationTime) {
- m_client->didFail(NOT_READABLE_ERR);
- return;
- }
-
- // Jump to the beginning position if the file has been sliced.
- if (fileRangeItem->start() > 0) {
- if (seekFile(m_handle, fileRangeItem->start(), SeekFromBeginning) < 0) {
- m_client->didFail(NOT_READABLE_ERR);
- return;
- }
- }
- }
+ m_totalBytesToRead = length;
+ m_bytesProcessed = 0;
- // Get the size.
- m_totalBytesToRead = blob->size();
- m_client->didGetSize(m_totalBytesToRead);
+ return 0;
}
-void FileStream::openForWrite(const String&)
+ExceptionCode FileStream::openForWrite(const String&)
{
- ASSERT(!isMainThread());
// FIXME: to be implemented.
+ return NOT_SUPPORTED_ERR;
}
void FileStream::close()
{
- ASSERT(!isMainThread());
if (isHandleValid(m_handle)) {
closeFile(m_handle);
m_handle = invalidPlatformFileHandle;
}
}
-void FileStream::read(char* buffer, int length)
+int FileStream::read(char* buffer, int bufferSize)
{
- ASSERT(!isMainThread());
-
- if (!isHandleValid(m_handle)) {
- m_client->didFail(NOT_READABLE_ERR);
- return;
- }
-
- if (m_bytesProcessed >= m_totalBytesToRead) {
- m_client->didFinish();
- return;
- }
+ if (!isHandleValid(m_handle))
+ return -1;
long long remaining = m_totalBytesToRead - m_bytesProcessed;
- int bytesToRead = (remaining < length) ? static_cast<int>(remaining) : length;
- int bytesRead = readFromFile(m_handle, buffer, bytesToRead);
- if (bytesRead < 0) {
- m_client->didFail(NOT_READABLE_ERR);
- return;
- }
-
- if (!bytesRead) {
- m_client->didFinish();
- return;
- }
-
- m_bytesProcessed += bytesRead;
- m_client->didRead(buffer, bytesRead);
+ int bytesToRead = (remaining < bufferSize) ? static_cast<int>(remaining) : bufferSize;
+ int bytesRead = 0;
+ if (bytesToRead > 0)
+ bytesRead = readFromFile(m_handle, buffer, bytesToRead);
+ if (bytesRead < 0)
+ return -1;
+ if (bytesRead > 0)
+ m_bytesProcessed += bytesRead;
+
+ return bytesRead;
}
-void FileStream::write(Blob*, long long, int)
+int FileStream::write(Blob*, long long, int)
{
- ASSERT(!isMainThread());
// FIXME: to be implemented.
+ return -1;
}
-void FileStream::truncate(long long)
+ExceptionCode FileStream::truncate(long long)
{
- ASSERT(!isMainThread());
// FIXME: to be implemented.
+ return NOT_SUPPORTED_ERR;
}
} // namespace WebCore
diff --git a/WebCore/html/FileStream.h b/WebCore/html/FileStream.h
index b5eccd4..e299fe4 100644
--- a/WebCore/html/FileStream.h
+++ b/WebCore/html/FileStream.h
@@ -33,7 +33,7 @@
#if ENABLE(BLOB) || ENABLE(FILE_WRITER)
-#include "FileStreamClient.h"
+#include "ExceptionCode.h"
#include "FileSystem.h"
#include <wtf/Forward.h>
#include <wtf/PassRefPtr.h>
@@ -43,29 +43,52 @@ namespace WebCore {
class Blob;
-// All methods are synchronous and should be called on File or Worker thread.
+// All methods are synchronous.
class FileStream : public RefCounted<FileStream> {
public:
- static PassRefPtr<FileStream> create(FileStreamClient* client)
+ static PassRefPtr<FileStream> create()
{
- return adoptRef(new FileStream(client));
+ return adoptRef(new FileStream());
}
virtual ~FileStream();
+ // FIXME: To be removed when we switch to using BlobData.
void start();
+
+ // Aborts the operation.
void stop();
- void openForRead(Blob*);
- void openForWrite(const String& path);
+ // Gets the size of a file. Also validates if the file has been changed or not if the expected modification time is provided, i.e. non-zero.
+ // Returns total number of bytes if successful. -1 otherwise.
+ long long getSize(const String& path, double expectedModificationTime);
+
+ // Opens a file for reading. The reading starts at the specified offset and lasts till the specified length.
+ // Returns 0 on success. Exception code otherwise.
+ ExceptionCode openForRead(const String& path, long long offset, long long length);
+
+ // Opens a file for writing.
+ // Returns 0 on success. Exception code otherwise.
+ ExceptionCode openForWrite(const String& path);
+
+ // Closes the file.
void close();
- void read(char* buffer, int length);
- void write(Blob* blob, long long position, int length);
- void truncate(long long position);
+
+ // Reads a file into the provided data buffer.
+ // Returns number of bytes being read on success. -1 otherwise.
+ // If 0 is returned, it means that the reading is completed.
+ int read(char* buffer, int length);
+
+ // Writes a blob to the file.
+ // Returns number of bytes being written on success. -1 otherwise.
+ int write(Blob*, long long position, int length);
+
+ // Truncates the file to the specified position.
+ // Returns 0 on success. Exception code otherwise.
+ ExceptionCode truncate(long long position);
private:
- FileStream(FileStreamClient*);
+ FileStream();
- FileStreamClient* m_client;
PlatformFileHandle m_handle;
long long m_bytesProcessed;
long long m_totalBytesToRead;
diff --git a/WebCore/html/FileStreamClient.h b/WebCore/html/FileStreamClient.h
index 2e7091f..440d2fb 100644
--- a/WebCore/html/FileStreamClient.h
+++ b/WebCore/html/FileStreamClient.h
@@ -40,16 +40,18 @@ namespace WebCore {
class FileStreamClient {
public:
// For reading.
- virtual void didRead(const char*, int) { }
+ virtual void didRead(int) { }
// For writing.
virtual void didWrite(int) { }
+ virtual void didTruncate(ExceptionCode) { }
- // For both reading and writing.
+ // FIXME: To be removed when we switch to using BlobData.
virtual void didStart() { }
+
+ // For both reading and writing.
+ virtual void didOpen(ExceptionCode) { }
virtual void didStop() { }
- virtual void didFinish() { }
- virtual void didFail(ExceptionCode) { }
virtual void didGetSize(long long) { }
protected:
diff --git a/WebCore/html/FileStreamProxy.cpp b/WebCore/html/FileStreamProxy.cpp
index e3b9e79..f50b7e8 100644
--- a/WebCore/html/FileStreamProxy.cpp
+++ b/WebCore/html/FileStreamProxy.cpp
@@ -37,6 +37,7 @@
#include "Blob.h"
#include "CrossThreadTask.h"
#include "FileStream.h"
+#include "FileStreamClient.h"
#include "FileThread.h"
#include "FileThreadTask.h"
#include "PlatformString.h"
@@ -47,7 +48,7 @@ namespace WebCore {
inline FileStreamProxy::FileStreamProxy(ScriptExecutionContext* context, FileStreamClient* client)
: m_context(context)
, m_client(client)
- , m_stream(FileStream::create(this))
+ , m_stream(FileStream::create())
{
}
@@ -59,7 +60,7 @@ PassRefPtr<FileStreamProxy> FileStreamProxy::create(ScriptExecutionContext* cont
// This is balanced by the deref in derefProxyOnContext below.
proxy->ref();
- proxy->fileThread()->postTask(createFileThreadTask(proxy->m_stream.get(), &FileStream::start));
+ proxy->fileThread()->postTask(createFileThreadTask(proxy.get(), &FileStreamProxy::startOnFileThread));
return proxy.release();
}
@@ -68,133 +69,150 @@ FileStreamProxy::~FileStreamProxy()
{
}
-void FileStreamProxy::openForRead(Blob* blob)
+FileThread* FileStreamProxy::fileThread()
{
- fileThread()->postTask(createFileThreadTask(m_stream.get(), &FileStream::openForRead, blob));
+ ASSERT(m_context->isContextThread());
+ ASSERT(m_context->fileThread());
+ return m_context->fileThread();
}
-void FileStreamProxy::openForWrite(const String& path)
+static void didStart(ScriptExecutionContext*, FileStreamProxy* proxy)
{
- fileThread()->postTask(createFileThreadTask(m_stream.get(), &FileStream::openForWrite, path));
+ if (proxy->client())
+ proxy->client()->didStart();
}
-void FileStreamProxy::close()
+void FileStreamProxy::startOnFileThread()
{
- fileThread()->postTask(createFileThreadTask(m_stream.get(), &FileStream::close));
+ m_stream->start();
+ m_context->postTask(createCallbackTask(&didStart, this));
}
-void FileStreamProxy::read(char* buffer, int length)
+void FileStreamProxy::stop()
{
- fileThread()->postTask(createFileThreadTask(m_stream.get(), &FileStream::read, buffer, length));
+ // Clear the client so that we won't be calling callbacks on the client.
+ m_client = 0;
+
+ fileThread()->unscheduleTasks(m_stream.get());
+ fileThread()->postTask(createFileThreadTask(this, &FileStreamProxy::stopOnFileThread));
}
-void FileStreamProxy::write(Blob* blob, long long position, int length)
+static void derefProxyOnContext(ScriptExecutionContext*, FileStreamProxy* proxy)
{
- fileThread()->postTask(createFileThreadTask(m_stream.get(), &FileStream::write, blob, position, length));
+ ASSERT(proxy->hasOneRef());
+ proxy->deref();
}
-void FileStreamProxy::truncate(long long position)
+void FileStreamProxy::stopOnFileThread()
{
- fileThread()->postTask(createFileThreadTask(m_stream.get(), &FileStream::truncate, position));
+ m_stream->stop();
+ m_context->postTask(createCallbackTask(&derefProxyOnContext, this));
}
-FileThread* FileStreamProxy::fileThread()
+static void didGetSize(ScriptExecutionContext*, FileStreamProxy* proxy, long long size)
{
- ASSERT(m_context->isContextThread());
- ASSERT(m_context->fileThread());
- return m_context->fileThread();
+ if (proxy->client())
+ proxy->client()->didGetSize(size);
}
-void FileStreamProxy::stop()
+void FileStreamProxy::getSize(const String& path, double expectedModificationTime)
{
- // Clear the client so that we won't be calling callbacks on the client.
- m_client = 0;
+ fileThread()->postTask(createFileThreadTask(this, &FileStreamProxy::getSizeOnFileThread, path, expectedModificationTime));
+}
- fileThread()->unscheduleTasks(m_stream.get());
- fileThread()->postTask(createFileThreadTask(m_stream.get(), &FileStream::stop));
+void FileStreamProxy::getSizeOnFileThread(const String& path, double expectedModificationTime)
+{
+ long long size = m_stream->getSize(path, expectedModificationTime);
+ m_context->postTask(createCallbackTask(&didGetSize, this, size));
}
-static void notifyGetSizeOnContext(ScriptExecutionContext*, FileStreamProxy* proxy, long long size)
+static void didOpen(ScriptExecutionContext*, FileStreamProxy* proxy, ExceptionCode ec)
{
if (proxy->client())
- proxy->client()->didGetSize(size);
+ proxy->client()->didOpen(ec);
}
-void FileStreamProxy::didGetSize(long long size)
+void FileStreamProxy::openForRead(const String& path, long long offset, long long length)
{
- ASSERT(!m_context->isContextThread());
- m_context->postTask(createCallbackTask(&notifyGetSizeOnContext, this, size));
+ fileThread()->postTask(createFileThreadTask(this, &FileStreamProxy::openForReadOnFileThread, path, offset, length));
}
-static void notifyReadOnContext(ScriptExecutionContext*, FileStreamProxy* proxy, const char* data, int bytesRead)
+void FileStreamProxy::openForReadOnFileThread(const String& path, long long offset, long long length)
{
- if (proxy->client())
- proxy->client()->didRead(data, bytesRead);
+ ExceptionCode ec = m_stream->openForRead(path, offset, length);
+ m_context->postTask(createCallbackTask(&didOpen, this, ec));
+}
+
+void FileStreamProxy::openForWrite(const String& path)
+{
+ fileThread()->postTask(createFileThreadTask(this, &FileStreamProxy::openForWriteOnFileThread, path));
}
-void FileStreamProxy::didRead(const char* data, int bytesRead)
+void FileStreamProxy::openForWriteOnFileThread(const String& path)
{
- ASSERT(!m_context->isContextThread());
- m_context->postTask(createCallbackTask(&notifyReadOnContext, this, data, bytesRead));
+ ExceptionCode ec = m_stream->openForWrite(path);
+ m_context->postTask(createCallbackTask(&didOpen, this, ec));
}
-static void notifyWriteOnContext(ScriptExecutionContext*, FileStreamProxy* proxy, int bytesWritten)
+void FileStreamProxy::close()
{
- if (proxy->client())
- proxy->client()->didWrite(bytesWritten);
+ fileThread()->postTask(createFileThreadTask(this, &FileStreamProxy::closeOnFileThread));
}
-void FileStreamProxy::didWrite(int bytesWritten)
+void FileStreamProxy::closeOnFileThread()
{
- ASSERT(!m_context->isContextThread());
- m_context->postTask(createCallbackTask(&notifyWriteOnContext, this, bytesWritten));
+ m_stream->close();
}
-static void notifyStartOnContext(ScriptExecutionContext*, FileStreamProxy* proxy)
+static void didRead(ScriptExecutionContext*, FileStreamProxy* proxy, int bytesRead)
{
if (proxy->client())
- proxy->client()->didStart();
+ proxy->client()->didRead(bytesRead);
}
-void FileStreamProxy::didStart()
+void FileStreamProxy::read(char* buffer, int length)
+{
+ fileThread()->postTask(createFileThreadTask(this, &FileStreamProxy::readOnFileThread, buffer, length));
+}
+
+void FileStreamProxy::readOnFileThread(char* buffer, int length)
{
- ASSERT(!m_context->isContextThread());
- m_context->postTask(createCallbackTask(&notifyStartOnContext, this));
+ int bytesRead = m_stream->read(buffer, length);
+ m_context->postTask(createCallbackTask(&didRead, this, bytesRead));
}
-static void notifyFinishOnContext(ScriptExecutionContext*, FileStreamProxy* proxy)
+static void didWrite(ScriptExecutionContext*, FileStreamProxy* proxy, int bytesWritten)
{
if (proxy->client())
- proxy->client()->didFinish();
+ proxy->client()->didWrite(bytesWritten);
}
-void FileStreamProxy::didFinish()
+void FileStreamProxy::write(Blob* blob, long long position, int length)
{
- ASSERT(!m_context->isContextThread());
- m_context->postTask(createCallbackTask(&notifyFinishOnContext, this));
+ fileThread()->postTask(createFileThreadTask(this, &FileStreamProxy::writeOnFileThread, blob, position, length));
}
-static void notifyFailOnContext(ScriptExecutionContext*, FileStreamProxy* proxy, ExceptionCode ec)
+void FileStreamProxy::writeOnFileThread(Blob* blob, long long position, int length)
{
- if (proxy->client())
- proxy->client()->didFail(ec);
+ int bytesWritten = m_stream->write(blob, position, length);
+ m_context->postTask(createCallbackTask(&didWrite, this, bytesWritten));
}
-void FileStreamProxy::didFail(ExceptionCode ec)
+static void didTruncate(ScriptExecutionContext*, FileStreamProxy* proxy, ExceptionCode ec)
{
- ASSERT(!m_context->isContextThread());
- m_context->postTask(createCallbackTask(&notifyFailOnContext, this, ec));
+ if (proxy->client())
+ proxy->client()->didTruncate(ec);
}
-static void derefProxyOnContext(ScriptExecutionContext*, FileStreamProxy* proxy)
+void FileStreamProxy::truncate(long long position)
{
- ASSERT(proxy->hasOneRef());
- proxy->deref();
+ fileThread()->postTask(createFileThreadTask(this, &FileStreamProxy::truncateOnFileThread, position));
}
-void FileStreamProxy::didStop()
+void FileStreamProxy::truncateOnFileThread(long long position)
{
- m_context->postTask(createCallbackTask(&derefProxyOnContext, this));
+ ExceptionCode ec = m_stream->truncate(position);
+ m_context->postTask(createCallbackTask(&didTruncate, this, ec));
}
} // namespace WebCore
diff --git a/WebCore/html/FileStreamProxy.h b/WebCore/html/FileStreamProxy.h
index 8523d4a..1d03a58 100644
--- a/WebCore/html/FileStreamProxy.h
+++ b/WebCore/html/FileStreamProxy.h
@@ -34,7 +34,6 @@
#if ENABLE(BLOB) || ENABLE(FILE_WRITER)
-#include "FileStreamClient.h"
#include <wtf/Forward.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
@@ -44,20 +43,22 @@ namespace WebCore {
class Blob;
class FileStream;
+class FileStreamClient;
class FileThread;
class ScriptExecutionContext;
-// A proxy module that calls corresponding FileStream methods on the file thread. Note: you must call stop() first and then release the reference to destruct the FileStreamProxy instance.
-class FileStreamProxy : public RefCounted<FileStreamProxy>, public FileStreamClient {
+// A proxy module that asynchronously calls corresponding FileStream methods on the file thread. Note: you must call stop() first and then release the reference to destruct the FileStreamProxy instance.
+class FileStreamProxy : public RefCounted<FileStreamProxy> {
public:
static PassRefPtr<FileStreamProxy> create(ScriptExecutionContext*, FileStreamClient*);
virtual ~FileStreamProxy();
- void openForRead(Blob* blob);
+ void getSize(const String& path, double expectedModificationTime);
+ void openForRead(const String& path, long long offset, long long length);
void openForWrite(const String& path);
void close();
void read(char* buffer, int length);
- void write(Blob* blob, long long position, int length);
+ void write(Blob*, long long position, int length);
void truncate(long long position);
// Stops the proxy and scedules it to be destructed. All the pending tasks will be aborted and the file stream will be closed.
@@ -69,17 +70,19 @@ public:
private:
FileStreamProxy(ScriptExecutionContext*, FileStreamClient*);
- // FileStreamClient methods.
- virtual void didGetSize(long long);
- virtual void didRead(const char*, int);
- virtual void didWrite(int);
- virtual void didFinish();
- virtual void didFail(ExceptionCode);
- virtual void didStart();
- virtual void didStop();
-
FileThread* fileThread();
+ // Called on File thread.
+ void startOnFileThread();
+ void stopOnFileThread();
+ void getSizeOnFileThread(const String& path, double expectedModificationTime);
+ void openForReadOnFileThread(const String& path, long long offset, long long length);
+ void openForWriteOnFileThread(const String& path);
+ void closeOnFileThread();
+ void readOnFileThread(char* buffer, int length);
+ void writeOnFileThread(Blob*, long long position, int length);
+ void truncateOnFileThread(long long position);
+
RefPtr<ScriptExecutionContext> m_context;
FileStreamClient* m_client;
RefPtr<FileStream> m_stream;
diff --git a/WebCore/html/FileThreadTask.h b/WebCore/html/FileThreadTask.h
index 09b647f..3443457 100644
--- a/WebCore/html/FileThreadTask.h
+++ b/WebCore/html/FileThreadTask.h
@@ -39,11 +39,11 @@
namespace WebCore {
-template<typename R, typename T>
+template<typename T>
class FileThreadTask0 : public FileThread::Task {
public:
- typedef R (T::*Method)();
- typedef FileThreadTask0<R, T> FileThreadTaskImpl;
+ typedef void (T::*Method)();
+ typedef FileThreadTask0<T> FileThreadTaskImpl;
static PassOwnPtr<FileThreadTaskImpl> create(T* instance, Method method)
{
@@ -66,11 +66,11 @@ private:
Method m_method;
};
-template<typename R, typename T, typename P1, typename MP1>
+template<typename T, typename P1, typename MP1>
class FileThreadTask1 : public FileThread::Task {
public:
- typedef R (T::*Method)(MP1);
- typedef FileThreadTask1<R, T, P1, MP1> FileThreadTaskImpl;
+ typedef void (T::*Method)(MP1);
+ typedef FileThreadTask1<T, P1, MP1> FileThreadTaskImpl;
typedef typename CrossThreadTaskTraits<P1>::ParamType Param1;
static PassOwnPtr<FileThreadTaskImpl> create(T* instance, Method method, Param1 parameter1)
@@ -96,11 +96,11 @@ private:
P1 m_parameter1;
};
-template<typename R, typename T, typename P1, typename MP1, typename P2, typename MP2>
+template<typename T, typename P1, typename MP1, typename P2, typename MP2>
class FileThreadTask2 : public FileThread::Task {
public:
- typedef R (T::*Method)(MP1, MP2);
- typedef FileThreadTask2<R, T, P1, MP1, P2, MP2> FileThreadTaskImpl;
+ typedef void (T::*Method)(MP1, MP2);
+ typedef FileThreadTask2<T, P1, MP1, P2, MP2> FileThreadTaskImpl;
typedef typename CrossThreadTaskTraits<P1>::ParamType Param1;
typedef typename CrossThreadTaskTraits<P2>::ParamType Param2;
@@ -129,11 +129,11 @@ private:
P2 m_parameter2;
};
-template<typename R, typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3>
+template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3>
class FileThreadTask3 : public FileThread::Task {
public:
typedef void (T::*Method)(MP1, MP2, MP3);
- typedef FileThreadTask3<R, T, P1, MP1, P2, MP2, P3, MP3> FileThreadTaskImpl;
+ typedef FileThreadTask3<T, P1, MP1, P2, MP2, P3, MP3> FileThreadTaskImpl;
typedef typename CrossThreadTaskTraits<P1>::ParamType Param1;
typedef typename CrossThreadTaskTraits<P2>::ParamType Param2;
typedef typename CrossThreadTaskTraits<P3>::ParamType Param3;
@@ -165,56 +165,56 @@ private:
P3 m_parameter3;
};
-template<typename R, typename T>
+template<typename T>
PassOwnPtr<FileThread::Task> createFileThreadTask(
T* const callee,
- R (T::*method)());
+ void (T::*method)());
-template<typename R, typename T>
+template<typename T>
PassOwnPtr<FileThread::Task> createFileThreadTask(
T* const callee,
- R (T::*method)())
+ void (T::*method)())
{
- return FileThreadTask0<R, T>::create(
+ return FileThreadTask0<T>::create(
callee,
method);
}
-template<typename R, typename T, typename P1, typename MP1>
+template<typename T, typename P1, typename MP1>
PassOwnPtr<FileThread::Task> createFileThreadTask(
T* const callee,
- R (T::*method)(MP1),
+ void (T::*method)(MP1),
const P1& parameter1)
{
- return FileThreadTask1<R, T, typename CrossThreadCopier<P1>::Type, MP1>::create(
+ return FileThreadTask1<T, typename CrossThreadCopier<P1>::Type, MP1>::create(
callee,
method,
CrossThreadCopier<P1>::copy(parameter1));
}
-template<typename R, typename T, typename P1, typename MP1, typename P2, typename MP2>
+template<typename T, typename P1, typename MP1, typename P2, typename MP2>
PassOwnPtr<FileThread::Task> createFileThreadTask(
T* const callee,
- R (T::*method)(MP1, MP2),
+ void (T::*method)(MP1, MP2),
const P1& parameter1,
const P2& parameter2)
{
- return FileThreadTask2<R, T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2>::create(
+ return FileThreadTask2<T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2>::create(
callee,
method,
CrossThreadCopier<P1>::copy(parameter1),
CrossThreadCopier<P2>::copy(parameter2));
}
-template<typename R, typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3>
+template<typename T, typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3>
PassOwnPtr<FileThread::Task> createFileThreadTask(
T* const callee,
- R (T::*method)(MP1, MP2, MP3),
+ void (T::*method)(MP1, MP2, MP3),
const P1& parameter1,
const P2& parameter2,
const P3& parameter3)
{
- return FileThreadTask3<R, T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2, typename CrossThreadCopier<P3>::Type, MP3>::create(
+ return FileThreadTask3<T, typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2, typename CrossThreadCopier<P3>::Type, MP3>::create(
callee,
method,
CrossThreadCopier<P1>::copy(parameter1),
diff --git a/WebCore/html/HTMLAnchorElement.cpp b/WebCore/html/HTMLAnchorElement.cpp
index 0d2e92d..e1ee86a 100644
--- a/WebCore/html/HTMLAnchorElement.cpp
+++ b/WebCore/html/HTMLAnchorElement.cpp
@@ -381,11 +381,11 @@ void HTMLAnchorElement::setHost(const String& value)
if (!url.canSetHostOrPort())
return;
- int separator = value.find(':');
+ size_t separator = value.find(':');
if (!separator)
return;
- if (separator == -1)
+ if (separator == notFound)
url.setHostAndPort(value);
else {
unsigned portEnd;
diff --git a/WebCore/html/HTMLCanvasElement.cpp b/WebCore/html/HTMLCanvasElement.cpp
index ef5574a..84ab227 100644
--- a/WebCore/html/HTMLCanvasElement.cpp
+++ b/WebCore/html/HTMLCanvasElement.cpp
@@ -209,8 +209,7 @@ CanvasRenderingContext* HTMLCanvasElement::getContext(const String& type, Canvas
void HTMLCanvasElement::willDraw(const FloatRect& rect)
{
- if (m_imageBuffer)
- m_imageBuffer->clearImage();
+ m_copiedImage.clear(); // Clear our image snapshot if we have one.
if (RenderBox* ro = renderBox()) {
FloatRect destRect = ro->contentBoxRect();
@@ -233,6 +232,7 @@ void HTMLCanvasElement::reset()
return;
bool ok;
+ bool hadImageBuffer = hasCreatedImageBuffer();
int w = getAttribute(widthAttr).toInt(&ok);
if (!ok || w < 0)
w = DefaultWidth;
@@ -241,14 +241,13 @@ void HTMLCanvasElement::reset()
h = DefaultHeight;
IntSize oldSize = size();
- setSurfaceSize(IntSize(w, h));
+ setSurfaceSize(IntSize(w, h)); // The image buffer gets cleared here.
#if ENABLE(3D_CANVAS)
- if (m_context && m_context->is3d())
+ if (m_context && m_context->is3d() && oldSize != size())
static_cast<WebGLRenderingContext*>(m_context.get())->reshape(width(), height());
#endif
- bool hadImageBuffer = hasCreatedImageBuffer();
if (m_context && m_context->is2d())
static_cast<CanvasRenderingContext2D*>(m_context.get())->reset();
@@ -277,23 +276,21 @@ void HTMLCanvasElement::paint(GraphicsContext* context, const IntRect& r)
WebGLRenderingContext* context3D = 0;
if (m_context && m_context->is3d()) {
context3D = static_cast<WebGLRenderingContext*>(m_context.get());
- context3D->beginPaint();
+ if (!context3D->paintsIntoCanvasBuffer())
+ return;
+ context3D->paintRenderingResultsToCanvas();
}
#endif
if (hasCreatedImageBuffer()) {
ImageBuffer* imageBuffer = buffer();
if (imageBuffer) {
- Image* image = imageBuffer->imageForRendering();
- if (image)
- context->drawImage(image, DeviceColorSpace, r);
+ if (imageBuffer->drawsUsingCopy())
+ context->drawImage(copiedImage(), DeviceColorSpace, r);
+ else
+ context->drawImageBuffer(imageBuffer, DeviceColorSpace, r);
}
}
-
-#if ENABLE(3D_CANVAS)
- if (context3D)
- context3D->endPaint();
-#endif
}
#if ENABLE(3D_CANVAS)
@@ -325,6 +322,7 @@ void HTMLCanvasElement::setSurfaceSize(const IntSize& size)
m_size = size;
m_hasCreatedImageBuffer = false;
m_imageBuffer.clear();
+ m_copiedImage.clear();
}
String HTMLCanvasElement::toDataURL(const String& mimeType, const double* quality, ExceptionCode& ec)
@@ -405,6 +403,7 @@ void HTMLCanvasElement::createImageBuffer() const
return;
m_imageBuffer->context()->scale(FloatSize(size.width() / unscaledSize.width(), size.height() / unscaledSize.height()));
m_imageBuffer->context()->setShadowsIgnoreTransforms(true);
+ m_imageBuffer->context()->setImageInterpolationQuality(CanvasInterpolationQuality);
}
GraphicsContext* HTMLCanvasElement::drawingContext() const
@@ -419,6 +418,18 @@ ImageBuffer* HTMLCanvasElement::buffer() const
return m_imageBuffer.get();
}
+Image* HTMLCanvasElement::copiedImage() const
+{
+ if (!m_copiedImage && buffer())
+ m_copiedImage = buffer()->copyImage();
+ return m_copiedImage.get();
+}
+
+void HTMLCanvasElement::clearCopiedImage()
+{
+ m_copiedImage.clear();
+}
+
AffineTransform HTMLCanvasElement::baseTransform() const
{
ASSERT(m_hasCreatedImageBuffer);
diff --git a/WebCore/html/HTMLCanvasElement.h b/WebCore/html/HTMLCanvasElement.h
index 2e3570d..3270667 100644
--- a/WebCore/html/HTMLCanvasElement.h
+++ b/WebCore/html/HTMLCanvasElement.h
@@ -38,6 +38,7 @@ class CanvasContextAttributes;
class CanvasRenderingContext;
class GraphicsContext;
class HTMLCanvasElement;
+class Image;
class ImageBuffer;
class IntSize;
@@ -93,6 +94,8 @@ public:
CanvasRenderingContext* renderingContext() const { return m_context.get(); }
ImageBuffer* buffer() const;
+ Image* copiedImage() const;
+ void clearCopiedImage();
IntRect convertLogicalToDevice(const FloatRect&) const;
IntSize convertLogicalToDevice(const FloatSize&) const;
@@ -165,6 +168,8 @@ private:
// m_createdImageBuffer means we tried to malloc the buffer. We didn't necessarily get it.
mutable bool m_hasCreatedImageBuffer;
mutable OwnPtr<ImageBuffer> m_imageBuffer;
+
+ mutable RefPtr<Image> m_copiedImage; // FIXME: This is temporary for platforms that have to copy the image buffer to render (and for CSSCanvasValue).
};
} //namespace
diff --git a/WebCore/html/HTMLConstructionSite.cpp b/WebCore/html/HTMLConstructionSite.cpp
index 1a9a373..a25c7d9 100644
--- a/WebCore/html/HTMLConstructionSite.cpp
+++ b/WebCore/html/HTMLConstructionSite.cpp
@@ -39,7 +39,6 @@
#include "HTMLScriptElement.h"
#include "HTMLToken.h"
#include "HTMLTokenizer.h"
-#include "LegacyHTMLDocumentParser.h"
#include "LegacyHTMLTreeBuilder.h"
#include "LocalizedStrings.h"
#if ENABLE(MATHML)
@@ -93,11 +92,17 @@ PassRefPtr<ChildType> HTMLConstructionSite::attach(Node* parent, PassRefPtr<Chil
// doesn't. It feels like we're missing a concept somehow.
if (shouldFosterParent()) {
fosterParent(child.get());
- ASSERT(child->attached());
+ ASSERT(child->attached() || !child->parent()->attached());
return child.release();
}
parent->parserAddChild(child);
+
+ // An event handler (DOM Mutation, beforeload, et al.) could have removed
+ // the child, in which case we shouldn't try attaching it.
+ if (!child->parentNode())
+ return child.release();
+
// It's slightly unfortunate that we need to hold a reference to child
// here to call attach(). We should investigate whether we can rely on
// |parent| to hold a ref at this point. In the common case (at least
diff --git a/WebCore/html/HTMLDocument.cpp b/WebCore/html/HTMLDocument.cpp
index bc9de97..4e26c02 100644
--- a/WebCore/html/HTMLDocument.cpp
+++ b/WebCore/html/HTMLDocument.cpp
@@ -68,7 +68,6 @@
#include "HTMLBodyElement.h"
#include "HTMLElementFactory.h"
#include "HTMLNames.h"
-#include "LegacyHTMLDocumentParser.h"
#include "InspectorController.h"
#include "KURL.h"
#include "Page.h"
@@ -290,11 +289,7 @@ DocumentParser* HTMLDocument::createParser()
if (Page* page = this->page())
reportErrors = page->inspectorController()->windowVisible();
#endif
-
- if (settings() && settings()->html5ParserEnabled())
- return new HTMLDocumentParser(this, reportErrors);
-
- return new LegacyHTMLDocumentParser(this, reportErrors);
+ return new HTMLDocumentParser(this, reportErrors);
}
// --------------------------------------------------------------------------
@@ -328,9 +323,9 @@ void HTMLDocument::removeItemFromMap(HashCountedSet<AtomicStringImpl*>& map, con
{
if (name.isEmpty())
return;
+ map.remove(name.impl());
if (Frame* f = frame())
f->script()->namedItemRemoved(this, name);
- map.remove(name.impl());
}
void HTMLDocument::addNamedItem(const AtomicString& name)
diff --git a/WebCore/html/HTMLDocument.h b/WebCore/html/HTMLDocument.h
index 646e100..3b5fdfa 100644
--- a/WebCore/html/HTMLDocument.h
+++ b/WebCore/html/HTMLDocument.h
@@ -23,10 +23,10 @@
#ifndef HTMLDocument_h
#define HTMLDocument_h
-#include "AtomicStringHash.h"
#include "CachedResourceClient.h"
#include "Document.h"
#include <wtf/HashCountedSet.h>
+#include <wtf/text/AtomicStringHash.h>
namespace WebCore {
diff --git a/WebCore/html/HTMLDocumentParser.h b/WebCore/html/HTMLDocumentParser.h
index d055861..d35cfaf 100644
--- a/WebCore/html/HTMLDocumentParser.h
+++ b/WebCore/html/HTMLDocumentParser.h
@@ -62,12 +62,14 @@ public:
static void parseDocumentFragment(const String&, DocumentFragment*, Element* contextElement, FragmentScriptingPermission = FragmentScriptingAllowed);
+protected:
+ virtual void insert(const SegmentedString&);
+ virtual void finish();
+
private:
// DocumentParser
virtual bool hasInsertionPoint();
- virtual void insert(const SegmentedString&);
virtual void append(const SegmentedString&);
- virtual void finish();
virtual bool finishWasCalled();
virtual bool processingData() const;
virtual void stopParsing();
diff --git a/WebCore/html/HTMLElement.cpp b/WebCore/html/HTMLElement.cpp
index 6fc53a2..ff25e62 100644
--- a/WebCore/html/HTMLElement.cpp
+++ b/WebCore/html/HTMLElement.cpp
@@ -275,18 +275,23 @@ String HTMLElement::outerHTML() const
return createMarkup(this);
}
-// FIXME: This method is unecessary with the new HTMLDocumentParser.
-PassRefPtr<DocumentFragment> HTMLElement::createContextualFragment(const String& markup, FragmentScriptingPermission scriptingPermission)
+static bool useLegacyTreeBuilder(Document* document)
+{
+ return !document || !document->settings() || !document->settings()->html5TreeBuilderEnabled();
+}
+
+// FIXME: This logic should move into Range::createContextualFragment
+PassRefPtr<DocumentFragment> HTMLElement::deprecatedCreateContextualFragment(const String& markup, FragmentScriptingPermission scriptingPermission)
{
// The following is in accordance with the definition as used by IE.
if (endTagRequirement() == TagStatusForbidden)
return 0;
- if (hasLocalName(colTag) || hasLocalName(colgroupTag) || hasLocalName(framesetTag) ||
- hasLocalName(headTag) || hasLocalName(styleTag) || hasLocalName(titleTag))
+ if (hasLocalName(colTag) || hasLocalName(colgroupTag) || hasLocalName(framesetTag)
+ || hasLocalName(headTag) || hasLocalName(styleTag) || hasLocalName(titleTag))
return 0;
- return Element::createContextualFragment(markup, scriptingPermission);
+ return Element::deprecatedCreateContextualFragment(markup, scriptingPermission);
}
static inline bool hasOneChild(ContainerNode* node)
@@ -339,23 +344,46 @@ static void replaceChildrenWithText(HTMLElement* element, const String& text, Ex
element->appendChild(textNode.release(), ec);
}
+// We may want to move a version of this function into DocumentFragment.h/cpp
+static PassRefPtr<DocumentFragment> createFragmentFromSource(const String& markup, Element* contextElement, ExceptionCode& ec)
+{
+ Document* document = contextElement->document();
+ RefPtr<DocumentFragment> fragment;
+
+ if (useLegacyTreeBuilder(document)) {
+ fragment = contextElement->deprecatedCreateContextualFragment(markup);
+ if (!fragment)
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return fragment;
+ }
+
+ fragment = DocumentFragment::create(document);
+ if (document->isHTMLDocument()) {
+ fragment->parseHTML(markup, contextElement);
+ return fragment;
+ }
+
+ bool wasValid = fragment->parseXML(markup, contextElement);
+ if (!wasValid) {
+ ec = INVALID_STATE_ERR;
+ return 0;
+ }
+ return fragment;
+}
+
void HTMLElement::setInnerHTML(const String& html, ExceptionCode& ec)
{
// FIXME: This code can be removed, it's handled by the HTMLDocumentParser correctly.
- if (hasLocalName(scriptTag) || hasLocalName(styleTag)) {
+ if (useLegacyTreeBuilder(document()) && (hasLocalName(scriptTag) || hasLocalName(styleTag))) {
// Script and CSS source shouldn't be parsed as HTML.
removeChildren();
appendChild(document()->createTextNode(html), ec);
return;
}
- RefPtr<DocumentFragment> fragment = createContextualFragment(html);
- if (!fragment) {
- ec = NO_MODIFICATION_ALLOWED_ERR;
- return;
- }
-
- replaceChildrenWithFragment(this, fragment.release(), ec);
+ RefPtr<DocumentFragment> fragment = createFragmentFromSource(html, this, ec);
+ if (fragment)
+ replaceChildrenWithFragment(this, fragment.release(), ec);
}
void HTMLElement::setOuterHTML(const String& html, ExceptionCode& ec)
@@ -365,17 +393,13 @@ void HTMLElement::setOuterHTML(const String& html, ExceptionCode& ec)
ec = NO_MODIFICATION_ALLOWED_ERR;
return;
}
-
HTMLElement* parent = static_cast<HTMLElement*>(p);
- RefPtr<DocumentFragment> fragment = parent->createContextualFragment(html);
- if (!fragment) {
- ec = NO_MODIFICATION_ALLOWED_ERR;
- return;
- }
- // FIXME: Why doesn't this have code to merge neighboring text nodes the way setOuterText does?
-
- parent->replaceChild(fragment.release(), this, ec);
+ RefPtr<DocumentFragment> fragment = createFragmentFromSource(html, parent, ec);
+ if (fragment) {
+ // FIXME: Why doesn't this have code to merge neighboring text nodes the way setOuterText does?
+ parent->replaceChild(fragment.release(), this, ec);
+ }
}
void HTMLElement::setInnerText(const String& text, ExceptionCode& ec)
@@ -549,13 +573,35 @@ Element* HTMLElement::insertAdjacentElement(const String& where, Element* newChi
return static_cast<Element*>(returnValue);
}
+// Step 3 of http://www.whatwg.org/specs/web-apps/current-work/multipage/apis-in-html-documents.html#insertadjacenthtml()
+static Element* contextElementForInsertion(const String& where, Element* element, ExceptionCode& ec)
+{
+ if (equalIgnoringCase(where, "beforeBegin") || equalIgnoringCase(where, "afterEnd")) {
+ Node* parent = element->parentNode();
+ if (parent && parent->isDocumentNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return 0;
+ }
+ ASSERT(!parent || parent->isElementNode());
+ return static_cast<Element*>(parent);
+ }
+ if (equalIgnoringCase(where, "afterBegin") || equalIgnoringCase(where, "beforeEnd"))
+ return element;
+ ec = SYNTAX_ERR;
+ return 0;
+}
+
void HTMLElement::insertAdjacentHTML(const String& where, const String& markup, ExceptionCode& ec)
{
RefPtr<DocumentFragment> fragment = document()->createDocumentFragment();
+ Element* contextElement = contextElementForInsertion(where, this, ec);
+ if (!contextElement)
+ return;
+
if (document()->isHTMLDocument())
- fragment->parseHTML(markup, this);
+ fragment->parseHTML(markup, contextElement);
else {
- if (!fragment->parseXML(markup, this))
+ if (!fragment->parseXML(markup, contextElement))
// FIXME: We should propagate a syntax error exception out here.
return;
}
diff --git a/WebCore/html/HTMLElement.h b/WebCore/html/HTMLElement.h
index 03449c9..8f54d3e 100644
--- a/WebCore/html/HTMLElement.h
+++ b/WebCore/html/HTMLElement.h
@@ -46,7 +46,8 @@ public:
String innerHTML() const;
String outerHTML() const;
- PassRefPtr<DocumentFragment> createContextualFragment(const String&, FragmentScriptingPermission = FragmentScriptingAllowed);
+ // deprecatedCreateContextualFragment logic should be moved into Range::createContextualFragment
+ PassRefPtr<DocumentFragment> deprecatedCreateContextualFragment(const String&, FragmentScriptingPermission = FragmentScriptingAllowed);
void setInnerHTML(const String&, ExceptionCode&);
void setOuterHTML(const String&, ExceptionCode&);
void setInnerText(const String&, ExceptionCode&);
diff --git a/WebCore/html/HTMLEmbedElement.cpp b/WebCore/html/HTMLEmbedElement.cpp
index 3f700ef..afa56d4 100644
--- a/WebCore/html/HTMLEmbedElement.cpp
+++ b/WebCore/html/HTMLEmbedElement.cpp
@@ -89,8 +89,8 @@ void HTMLEmbedElement::parseMappedAttribute(Attribute* attr)
if (attr->name() == typeAttr) {
m_serviceType = value.string().lower();
- int pos = m_serviceType.find(";");
- if (pos != -1)
+ size_t pos = m_serviceType.find(";");
+ if (pos != notFound)
m_serviceType = m_serviceType.left(pos);
if (!isImageType() && m_imageLoader)
m_imageLoader.clear();
diff --git a/WebCore/html/HTMLEntityNames.gperf b/WebCore/html/HTMLEntityNames.gperf
deleted file mode 100644
index c665efe..0000000
--- a/WebCore/html/HTMLEntityNames.gperf
+++ /dev/null
@@ -1,303 +0,0 @@
-%{
-/*
- Copyright (C) 1999 Lars Knoll (knoll@mpi-hd.mpg.de)
- Copyright (C) 2002, 2003, 2004, 2005 Apple Inc. All rights reserved.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-
- ----------------------------------------------------------------------------
-
- HTMLEntityNames.gperf: input file to generate a hash table for entities
- HTMLEntityNames.cpp: DO NOT EDIT! generated by WebCore/make-hash-tools.pl
-*/
-%}
-%struct-type
-struct Entity {
- const char *name;
- int code;
-};
-%language=ANSI-C
-%readonly-tables
-%global-table
-%compare-strncmp
-%define lookup-function-name findEntity
-%define hash-function-name entity_hash_function
-%includes
-%enum
-%%
-AElig, 0x00c6
-AMP, 38
-Aacute, 0x00c1
-Acirc, 0x00c2
-Agrave, 0x00c0
-Alpha, 0x0391
-Aring, 0x00c5
-Atilde, 0x00c3
-Auml, 0x00c4
-Beta, 0x0392
-COPY, 0x00a9
-Ccedil, 0x00c7
-Chi, 0x03a7
-Dagger, 0x2021
-Delta, 0x0394
-ETH, 0x00d0
-Eacute, 0x00c9
-Ecirc, 0x00ca
-Egrave, 0x00c8
-Epsilon, 0x0395
-Eta, 0x0397
-Euml, 0x00cb
-GT, 62
-Gamma, 0x0393
-Iacute, 0x00cd
-Icirc, 0x00ce
-Igrave, 0x00cc
-Iota, 0x0399
-Iuml, 0x00cf
-Kappa, 0x039a
-LT, 60
-Lambda, 0x039b
-Mu, 0x039c
-Ntilde, 0x00d1
-Nu, 0x039d
-OElig, 0x0152
-Oacute, 0x00d3
-Ocirc, 0x00d4
-Ograve, 0x00d2
-Omega, 0x03a9
-Omicron, 0x039f
-Oslash, 0x00d8
-Otilde, 0x00d5
-Ouml, 0x00d6
-Phi, 0x03a6
-Pi, 0x03a0
-Prime, 0x2033
-Psi, 0x03a8
-QUOT, 34
-REG, 0x00ae
-Rho, 0x03a1
-Scaron, 0x0160
-Sigma, 0x03a3
-THORN, 0x00de
-Tau, 0x03a4
-Theta, 0x0398
-Uacute, 0x00da
-Ucirc, 0x00db
-Ugrave, 0x00d9
-Upsilon, 0x03a5
-Uuml, 0x00dc
-Xi, 0x039e
-Yacute, 0x00dd
-Yuml, 0x0178
-Zeta, 0x0396
-aacute, 0x00e1
-acirc, 0x00e2
-acute, 0x00b4
-aelig, 0x00e6
-agrave, 0x00e0
-alefsym, 0x2135
-alpha, 0x03b1
-amp, 38
-and, 0x2227
-ang, 0x2220
-apos, 0x0027
-aring, 0x00e5
-asymp, 0x2248
-atilde, 0x00e3
-auml, 0x00e4
-bdquo, 0x201e
-beta, 0x03b2
-brvbar, 0x00a6
-bull, 0x2022
-cap, 0x2229
-ccedil, 0x00e7
-cedil, 0x00b8
-cent, 0x00a2
-chi, 0x03c7
-circ, 0x02c6
-clubs, 0x2663
-cong, 0x2245
-copy, 0x00a9
-crarr, 0x21b5
-cup, 0x222a
-curren, 0x00a4
-dArr, 0x21d3
-dagger, 0x2020
-darr, 0x2193
-deg, 0x00b0
-delta, 0x03b4
-diams, 0x2666
-divide, 0x00f7
-eacute, 0x00e9
-ecirc, 0x00ea
-egrave, 0x00e8
-empty, 0x2205
-emsp, 0x2003
-ensp, 0x2002
-epsilon, 0x03b5
-equiv, 0x2261
-eta, 0x03b7
-eth, 0x00f0
-euml, 0x00eb
-euro, 0x20ac
-exist, 0x2203
-fnof, 0x0192
-forall, 0x2200
-frac12, 0x00bd
-frac14, 0x00bc
-frac34, 0x00be
-frasl, 0x2044
-gamma, 0x03b3
-ge, 0x2265
-gt, 62
-hArr, 0x21d4
-harr, 0x2194
-hearts, 0x2665
-hellip, 0x2026
-iacute, 0x00ed
-icirc, 0x00ee
-iexcl, 0x00a1
-igrave, 0x00ec
-image, 0x2111
-infin, 0x221e
-int, 0x222b
-iota, 0x03b9
-iquest, 0x00bf
-isin, 0x2208
-iuml, 0x00ef
-kappa, 0x03ba
-lArr, 0x21d0
-lambda, 0x03bb
-lang, 0x3008
-laquo, 0x00ab
-larr, 0x2190
-lceil, 0x2308
-ldquo, 0x201c
-le, 0x2264
-lfloor, 0x230a
-lowast, 0x2217
-loz, 0x25ca
-lrm, 0x200e
-lsaquo, 0x2039
-lsquo, 0x2018
-lt, 60
-macr, 0x00af
-mdash, 0x2014
-micro, 0x00b5
-middot, 0x00b7
-minus, 0x2212
-mu, 0x03bc
-nabla, 0x2207
-nbsp, 0x00a0
-ndash, 0x2013
-ne, 0x2260
-ni, 0x220b
-not, 0x00ac
-notin, 0x2209
-nsub, 0x2284
-nsup, 0x2285
-ntilde, 0x00f1
-nu, 0x03bd
-oacute, 0x00f3
-ocirc, 0x00f4
-oelig, 0x0153
-ograve, 0x00f2
-oline, 0x203e
-omega, 0x03c9
-omicron, 0x03bf
-oplus, 0x2295
-or, 0x2228
-ordf, 0x00aa
-ordm, 0x00ba
-oslash, 0x00f8
-otilde, 0x00f5
-otimes, 0x2297
-ouml, 0x00f6
-para, 0x00b6
-part, 0x2202
-percnt, 0x0025
-permil, 0x2030
-perp, 0x22a5
-phi, 0x03c6
-pi, 0x03c0
-piv, 0x03d6
-plusmn, 0x00b1
-pound, 0x00a3
-prime, 0x2032
-prod, 0x220f
-prop, 0x221d
-psi, 0x03c8
-quot, 34
-rArr, 0x21d2
-radic, 0x221a
-rang, 0x3009
-raquo, 0x00bb
-rarr, 0x2192
-rceil, 0x2309
-rdquo, 0x201d
-real, 0x211c
-reg, 0x00ae
-rfloor, 0x230b
-rho, 0x03c1
-rlm, 0x200f
-rsaquo, 0x203a
-rsquo, 0x2019
-sbquo, 0x201a
-scaron, 0x0161
-sdot, 0x22c5
-sect, 0x00a7
-shy, 0x00ad
-sigma, 0x03c3
-sigmaf, 0x03c2
-sim, 0x223c
-spades, 0x2660
-sub, 0x2282
-sube, 0x2286
-sum, 0x2211
-sup, 0x2283
-sup1, 0x00b9
-sup2, 0x00b2
-sup3, 0x00b3
-supe, 0x2287
-supl, 0x00b9
-szlig, 0x00df
-tau, 0x03c4
-there4, 0x2234
-theta, 0x03b8
-thetasym, 0x03d1
-thinsp, 0x2009
-thorn, 0x00fe
-tilde, 0x02dc
-times, 0x00d7
-trade, 0x2122
-uArr, 0x21d1
-uacute, 0x00fa
-uarr, 0x2191
-ucirc, 0x00fb
-ugrave, 0x00f9
-uml, 0x00a8
-upsih, 0x03d2
-upsilon, 0x03c5
-uuml, 0x00fc
-weierp, 0x2118
-xi, 0x03be
-yacute, 0x00fd
-yen, 0x00a5
-yuml, 0x00ff
-zeta, 0x03b6
-zwj, 0x200d
-zwnj, 0x200c
-%%
diff --git a/WebCore/html/HTMLEntityParser.cpp b/WebCore/html/HTMLEntityParser.cpp
index 84b2006..f675844 100644
--- a/WebCore/html/HTMLEntityParser.cpp
+++ b/WebCore/html/HTMLEntityParser.cpp
@@ -28,21 +28,10 @@
#include "config.h"
#include "HTMLEntityParser.h"
+#include "HTMLEntitySearch.h"
+#include "HTMLEntityTable.h"
#include <wtf/Vector.h>
-// Use __GNUC__ instead of PLATFORM(GCC) to stay consistent with the gperf generated c file
-#ifdef __GNUC__
-// The main parser includes this too so we are getting two copies of the data. However, this way the code gets inlined.
-#include "HTMLEntityNames.cpp"
-#else
-// Not inlined for non-GCC compilers
-struct Entity {
- const char* name;
- int code;
-};
-const struct Entity* findEntity(register const char* str, register unsigned int len);
-#endif
-
using namespace WTF;
namespace WebCore {
@@ -113,7 +102,6 @@ unsigned consumeHTMLEntity(SegmentedString& source, bool& notEnoughCharacters, U
EntityState entityState = Initial;
unsigned result = 0;
Vector<UChar, 10> consumedCharacters;
- Vector<char, 10> entityName;
while (!source.isEmpty()) {
UChar cc = *source;
@@ -177,7 +165,7 @@ unsigned consumeHTMLEntity(SegmentedString& source, bool& notEnoughCharacters, U
else if (cc == ';') {
source.advancePastNonNewline();
return legalEntityFor(result);
- } else
+ } else
return legalEntityFor(result);
break;
}
@@ -192,48 +180,48 @@ unsigned consumeHTMLEntity(SegmentedString& source, bool& notEnoughCharacters, U
break;
}
case Named: {
- // FIXME: This code is wrong. We need to find the longest matching entity.
- // The examples from the spec are:
- // I'm &notit; I tell you
- // I'm &notin; I tell you
- // In the first case, "&not" is the entity. In the second
- // case, "&notin;" is the entity.
- // FIXME: Our list of HTML entities is incomplete.
- // FIXME: The number 8 below is bogus.
- while (!source.isEmpty() && entityName.size() <= 8) {
+ HTMLEntitySearch entitySearch;
+ while (!source.isEmpty()) {
cc = *source;
- if (cc == ';') {
- const Entity* entity = findEntity(entityName.data(), entityName.size());
- if (entity) {
- source.advanceAndASSERT(';');
- return entity->code;
- }
- break;
- }
- if (!isAlphaNumeric(cc)) {
- const Entity* entity = findEntity(entityName.data(), entityName.size());
- if (entity) {
- // HTML5 tells us to ignore this entity, for historical reasons,
- // if the lookhead character is '='.
- if (additionalAllowedCharacter && cc == '=')
- break;
- // Some entities require a terminating semicolon, whereas other
- // entities do not. The HTML5 spec has a giant list:
- //
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/named-character-references.html#named-character-references
- //
- // However, the list seems to boil down to this branch:
- if (entity->code > 255)
- break;
- return entity->code;
- }
+ entitySearch.advance(cc);
+ if (!entitySearch.isEntityPrefix())
break;
- }
- entityName.append(cc);
consumedCharacters.append(cc);
source.advanceAndASSERT(cc);
}
notEnoughCharacters = source.isEmpty();
+ if (notEnoughCharacters) {
+ // We can't an entity because there might be a longer entity
+ // that we could match if we had more data.
+ unconsumeCharacters(source, consumedCharacters);
+ return 0;
+ }
+ if (!entitySearch.mostRecentMatch()) {
+ ASSERT(!entitySearch.currentValue());
+ unconsumeCharacters(source, consumedCharacters);
+ return 0;
+ }
+ if (entitySearch.mostRecentMatch()->length != entitySearch.currentLength()) {
+ // We've consumed too many characters. We need to walk the
+ // source back to the point at which we had consumed an
+ // actual entity.
+ unconsumeCharacters(source, consumedCharacters);
+ consumedCharacters.clear();
+ const int length = entitySearch.mostRecentMatch()->length;
+ const UChar* reference = entitySearch.mostRecentMatch()->entity;
+ for (int i = 0; i < length; ++i) {
+ cc = *source;
+ ASSERT_UNUSED(reference, cc == *reference++);
+ consumedCharacters.append(cc);
+ source.advanceAndASSERT(cc);
+ ASSERT(!source.isEmpty());
+ }
+ cc = *source;
+ }
+ if (entitySearch.mostRecentMatch()->lastCharacter() == ';')
+ return entitySearch.mostRecentMatch()->value;
+ if (!additionalAllowedCharacter || !(isAlphaNumeric(cc) || cc == '='))
+ return entitySearch.mostRecentMatch()->value;
unconsumeCharacters(source, consumedCharacters);
return 0;
}
@@ -247,4 +235,23 @@ unsigned consumeHTMLEntity(SegmentedString& source, bool& notEnoughCharacters, U
return 0;
}
+UChar decodeNamedEntity(const char* name)
+{
+ HTMLEntitySearch search;
+ while (*name) {
+ search.advance(*name++);
+ if (!search.isEntityPrefix())
+ return 0;
+ }
+ search.advance(';');
+ UChar32 entityValue = search.currentValue();
+ if (U16_LENGTH(entityValue) != 1) {
+ // Callers need to move off this API if the entity table has values
+ // which do no fit in a 16 bit UChar!
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+ return static_cast<UChar>(entityValue);
+}
+
} // namespace WebCore
diff --git a/WebCore/html/HTMLEntityParser.h b/WebCore/html/HTMLEntityParser.h
index d37b0c3..1059b24 100644
--- a/WebCore/html/HTMLEntityParser.h
+++ b/WebCore/html/HTMLEntityParser.h
@@ -33,6 +33,9 @@ namespace WebCore {
unsigned consumeHTMLEntity(SegmentedString&, bool& notEnoughCharacters, UChar additionalAllowedCharacter = '\0');
+// Used by the XML parser. Not suitable for use in HTML parsing. Use consumeHTMLEntity instead.
+UChar decodeNamedEntity(const char*);
+
}
#endif
diff --git a/WebCore/html/HTMLEntitySearch.cpp b/WebCore/html/HTMLEntitySearch.cpp
new file mode 100644
index 0000000..580609e
--- /dev/null
+++ b/WebCore/html/HTMLEntitySearch.cpp
@@ -0,0 +1,132 @@
+/*
+ * 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 "HTMLEntitySearch.h"
+
+#include "HTMLEntityTable.h"
+
+namespace WebCore {
+
+namespace {
+
+const HTMLEntityTableEntry* halfway(const HTMLEntityTableEntry* left, const HTMLEntityTableEntry* right)
+{
+ return &left[(right - left) / 2];
+}
+
+}
+
+HTMLEntitySearch::HTMLEntitySearch()
+ : m_currentLength(0)
+ , m_currentValue(0)
+ , m_mostRecentMatch(0)
+ , m_first(HTMLEntityTable::firstEntry())
+ , m_last(HTMLEntityTable::lastEntry())
+{
+}
+
+HTMLEntitySearch::CompareResult HTMLEntitySearch::compare(const HTMLEntityTableEntry* entry, UChar nextCharacter) const
+{
+ if (entry->length < m_currentLength + 1)
+ return Before;
+ UChar entryNextCharacter = entry->entity[m_currentLength];
+ if (entryNextCharacter == nextCharacter)
+ return Prefix;
+ return entryNextCharacter < nextCharacter ? Before : After;
+}
+
+const HTMLEntityTableEntry* HTMLEntitySearch::findFirst(UChar nextCharacter) const
+{
+ const HTMLEntityTableEntry* left = m_first;
+ const HTMLEntityTableEntry* right = m_last;
+ if (left == right)
+ return left;
+ CompareResult result = compare(left, nextCharacter);
+ if (result == Prefix)
+ return left;
+ if (result == After)
+ return right;
+ while (left + 1 < right) {
+ const HTMLEntityTableEntry* probe = halfway(left, right);
+ result = compare(probe, nextCharacter);
+ if (result == Before)
+ left = probe;
+ else {
+ ASSERT(result == After || result == Prefix);
+ right = probe;
+ }
+ }
+ ASSERT(left + 1 == right);
+ return right;
+}
+
+const HTMLEntityTableEntry* HTMLEntitySearch::findLast(UChar nextCharacter) const
+{
+ const HTMLEntityTableEntry* left = m_first;
+ const HTMLEntityTableEntry* right = m_last;
+ if (left == right)
+ return right;
+ CompareResult result = compare(right, nextCharacter);
+ if (result == Prefix)
+ return right;
+ if (result == Before)
+ return left;
+ while (left + 1 < right) {
+ const HTMLEntityTableEntry* probe = halfway(left, right);
+ result = compare(probe, nextCharacter);
+ if (result == After)
+ right = probe;
+ else {
+ ASSERT(result == Before || result == Prefix);
+ left = probe;
+ }
+ }
+ ASSERT(left + 1 == right);
+ return left;
+}
+
+void HTMLEntitySearch::advance(UChar nextCharacter)
+{
+ ASSERT(isEntityPrefix());
+ if (!m_currentLength) {
+ m_first = HTMLEntityTable::firstEntryStartingWith(nextCharacter);
+ m_last = HTMLEntityTable::lastEntryStartingWith(nextCharacter);
+ } else {
+ m_first = findFirst(nextCharacter);
+ m_last = findLast(nextCharacter);
+ if (m_first == m_last && compare(m_first, nextCharacter) != Prefix)
+ return fail();
+ }
+ ++m_currentLength;
+ if (m_first->length != m_currentLength) {
+ m_currentValue = 0;
+ return;
+ }
+ m_mostRecentMatch = m_first;
+ m_currentValue = m_mostRecentMatch->value;
+}
+
+}
diff --git a/WebCore/html/canvas/CanvasNumberArray.h b/WebCore/html/HTMLEntitySearch.h
index 09714a0..11a23ae 100644
--- a/WebCore/html/canvas/CanvasNumberArray.h
+++ b/WebCore/html/HTMLEntitySearch.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * 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
@@ -10,10 +10,10 @@
* 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
+ * 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 COMPUTER, INC. OR
+ * 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
@@ -23,32 +23,53 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef CanvasNumberArray_h
-#define CanvasNumberArray_h
+#ifndef HTMLEntitySearch_h
+#define HTMLEntitySearch_h
-#include <wtf/Forward.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
-#include <wtf/Vector.h>
-#include <limits>
+#include "PlatformString.h"
namespace WebCore {
- class CanvasNumberArray : public RefCounted<CanvasNumberArray> {
- public:
- static PassRefPtr<CanvasNumberArray> create(unsigned length);
-
- Vector<float>& data() { return m_data; }
- const Vector<float>& data() const { return m_data; }
+struct HTMLEntityTableEntry;
- unsigned length() const { return m_data.size(); }
- float item(unsigned index) const { return (index >= m_data.size()) ? 0 : m_data[index]; }
+class HTMLEntitySearch {
+public:
+ HTMLEntitySearch();
- private:
- CanvasNumberArray(unsigned length);
- Vector<float> m_data;
+ void advance(UChar);
+
+ bool isEntityPrefix() const { return !!m_first; }
+ int currentValue() const { return m_currentValue; }
+ int currentLength() const { return m_currentLength; }
+
+ const HTMLEntityTableEntry* mostRecentMatch() const { return m_mostRecentMatch; }
+
+private:
+ enum CompareResult {
+ Before,
+ Prefix,
+ After,
};
-
-} // namespace WebCore
-#endif // CanvasNumberArray_h
+ CompareResult compare(const HTMLEntityTableEntry*, UChar) const;
+ const HTMLEntityTableEntry* findFirst(UChar) const;
+ const HTMLEntityTableEntry* findLast(UChar) const;
+
+ void fail()
+ {
+ m_currentValue = 0;
+ m_first = 0;
+ m_last = 0;
+ }
+
+ int m_currentLength;
+ int m_currentValue;
+
+ const HTMLEntityTableEntry* m_mostRecentMatch;
+ const HTMLEntityTableEntry* m_first;
+ const HTMLEntityTableEntry* m_last;
+};
+
+}
+
+#endif
diff --git a/WebCore/html/canvas/CanvasNumberArray.cpp b/WebCore/html/HTMLEntityTable.h
index 6cbdfff..3734c34 100644
--- a/WebCore/html/canvas/CanvasNumberArray.cpp
+++ b/WebCore/html/HTMLEntityTable.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Apple Inc. All rights reserved.
+ * 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
@@ -10,10 +10,10 @@
* 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
+ * 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 COMPUTER, INC. OR
+ * 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
@@ -23,25 +23,30 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "config.h"
+#ifndef HTMLEntityTable_h
+#define HTMLEntityTable_h
-#if ENABLE(3D_CANVAS)
-
-#include "CanvasNumberArray.h"
#include "PlatformString.h"
namespace WebCore {
-
-PassRefPtr<CanvasNumberArray> CanvasNumberArray::create(unsigned length)
-{
- return adoptRef(new CanvasNumberArray(length));
-}
-CanvasNumberArray::CanvasNumberArray(unsigned length)
- : m_data(length)
-{
-}
+struct HTMLEntityTableEntry {
+ UChar lastCharacter() const { return entity[length - 1]; }
+
+ const UChar* entity;
+ int length;
+ int value;
+};
+
+class HTMLEntityTable {
+public:
+ static const HTMLEntityTableEntry* firstEntry();
+ static const HTMLEntityTableEntry* lastEntry();
+
+ static const HTMLEntityTableEntry* firstEntryStartingWith(UChar);
+ static const HTMLEntityTableEntry* lastEntryStartingWith(UChar);
+};
}
-#endif // ENABLE(3D_CANVAS)
+#endif
diff --git a/WebCore/html/HTMLFormControlElement.cpp b/WebCore/html/HTMLFormControlElement.cpp
index 5103bfa..ae1ac62 100644
--- a/WebCore/html/HTMLFormControlElement.cpp
+++ b/WebCore/html/HTMLFormControlElement.cpp
@@ -30,6 +30,7 @@
#include "Chrome.h"
#include "ChromeClient.h"
#include "Document.h"
+#include "DocumentParser.h"
#include "ElementRareData.h"
#include "Event.h"
#include "EventHandler.h"
@@ -39,7 +40,6 @@
#include "HTMLInputElement.h"
#include "HTMLNames.h"
#include "LegacyHTMLTreeBuilder.h"
-#include "LegacyHTMLDocumentParser.h"
#include "LabelsNodeList.h"
#include "Page.h"
#include "RenderBox.h"
@@ -526,7 +526,7 @@ static bool isNotLineBreak(UChar ch) { return ch != newlineCharacter && ch != ca
bool HTMLTextFormControlElement::isPlaceholderEmpty() const
{
const AtomicString& attributeValue = getAttribute(placeholderAttr);
- return attributeValue.string().find(isNotLineBreak) == -1;
+ return attributeValue.string().find(isNotLineBreak) == notFound;
}
bool HTMLTextFormControlElement::placeholderShouldBeVisible() const
diff --git a/WebCore/html/HTMLInputElement.cpp b/WebCore/html/HTMLInputElement.cpp
index 8c759cb..50b6ed0 100644
--- a/WebCore/html/HTMLInputElement.cpp
+++ b/WebCore/html/HTMLInputElement.cpp
@@ -65,7 +65,6 @@
#include "RenderTheme.h"
#include "ScriptEventListener.h"
#include "StepRange.h"
-#include "StringHash.h"
#include "TextEvent.h"
#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS
#include "WebViewCore.h"
@@ -74,6 +73,7 @@
#include <wtf/HashMap.h>
#include <wtf/MathExtras.h>
#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringHash.h>
using namespace std;
diff --git a/WebCore/html/HTMLInputElement.h b/WebCore/html/HTMLInputElement.h
index 72ac589..18cbaa4 100644
--- a/WebCore/html/HTMLInputElement.h
+++ b/WebCore/html/HTMLInputElement.h
@@ -101,6 +101,7 @@ public:
virtual bool isSearchField() const { return m_type == SEARCH; }
virtual bool isInputTypeHidden() const { return m_type == HIDDEN; }
virtual bool isPasswordField() const { return m_type == PASSWORD; }
+ virtual bool isCheckbox() const { return m_type == CHECKBOX; }
bool isTelephoneField() const { return m_type == TELEPHONE; }
bool isNumberField() const { return m_type == NUMBER; }
bool isEmailField() const { return m_type == EMAIL; }
diff --git a/WebCore/html/HTMLLinkElement.cpp b/WebCore/html/HTMLLinkElement.cpp
index a638572..c778b6f 100644
--- a/WebCore/html/HTMLLinkElement.cpp
+++ b/WebCore/html/HTMLLinkElement.cpp
@@ -51,7 +51,6 @@ inline HTMLLinkElement::HTMLLinkElement(const QualifiedName& tagName, Document*
, m_disabledState(Unset)
, m_loading(false)
, m_createdByParser(createdByParser)
- , m_shouldProcessAfterAttach(false)
{
ASSERT(hasTagName(linkTag));
}
@@ -260,28 +259,12 @@ void HTMLLinkElement::process()
document()->updateStyleSelector();
}
}
-
-void HTMLLinkElement::processCallback(Node* node)
-{
- ASSERT_ARG(node, node && node->hasTagName(linkTag));
- static_cast<HTMLLinkElement*>(node)->process();
-}
void HTMLLinkElement::insertedIntoDocument()
{
HTMLElement::insertedIntoDocument();
document()->addStyleSheetCandidateNode(this, m_createdByParser);
- // Since processing a stylesheet link causes a beforeload event
- // to fire, it is possible for JavaScript to remove the element in the midst
- // of it being inserted into the DOM, which can lead to assertion failures
- // and crashes. Avoid this by postponing the beforeload/load until after
- // attach if there are beforeload listeners.
- if (document()->hasListenerType(Document::BEFORELOAD_LISTENER)) {
- m_shouldProcessAfterAttach = true;
- return;
- }
-
process();
}
@@ -294,20 +277,8 @@ void HTMLLinkElement::removedFromDocument()
// FIXME: It's terrible to do a synchronous update of the style selector just because a <style> or <link> element got removed.
if (document()->renderer())
document()->updateStyleSelector();
-
- m_shouldProcessAfterAttach = false;
}
-void HTMLLinkElement::attach()
-{
- if (m_shouldProcessAfterAttach) {
- m_shouldProcessAfterAttach = false;
- queuePostAttachCallback(&HTMLLinkElement::processCallback, this);
- }
-
- HTMLElement::attach();
-}
-
void HTMLLinkElement::finishParsingChildren()
{
m_createdByParser = false;
diff --git a/WebCore/html/HTMLLinkElement.h b/WebCore/html/HTMLLinkElement.h
index 057cccc..6d7643a 100644
--- a/WebCore/html/HTMLLinkElement.h
+++ b/WebCore/html/HTMLLinkElement.h
@@ -77,9 +77,6 @@ public:
bool isDisabled() const { return m_disabledState == Disabled; }
bool isEnabledViaScript() const { return m_disabledState == EnabledViaScript; }
bool isIcon() const { return m_relAttribute.m_isIcon; }
-
- virtual void attach();
- virtual bool canLazyAttach() { return false; }
private:
virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; }
@@ -137,7 +134,6 @@ private:
RelAttribute m_relAttribute;
bool m_loading;
bool m_createdByParser;
- bool m_shouldProcessAfterAttach;
};
} //namespace
diff --git a/WebCore/html/HTMLMediaElement.cpp b/WebCore/html/HTMLMediaElement.cpp
index 94c0dd2..13b7807 100644
--- a/WebCore/html/HTMLMediaElement.cpp
+++ b/WebCore/html/HTMLMediaElement.cpp
@@ -112,7 +112,6 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* doc)
, m_processingMediaPlayerCallback(0)
, m_playing(false)
, m_isWaitingUntilMediaCanStart(false)
- , m_processingLoad(false)
, m_delayingTheLoadEvent(false)
, m_haveFiredLoadedData(false)
, m_inActiveDocument(true)
@@ -512,7 +511,10 @@ void HTMLMediaElement::prepareForLoad()
#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO)
m_player = MediaPlayer::create(this);
#else
- createMediaPlayerProxy();
+ if (m_player)
+ m_player->cancelLoad();
+ else
+ createMediaPlayerProxy();
#endif
// 4 - If the media element's networkState is not set to NETWORK_EMPTY, then run these substeps
@@ -532,6 +534,16 @@ void HTMLMediaElement::prepareForLoad()
m_error = 0;
m_autoplaying = true;
+ // 7 - Invoke the media element's resource selection algorithm.
+
+ // 8 - Note: Playback of any previously playing media resource for this element stops.
+
+ // The resource selection algorithm
+ // 1 - Set the networkState to NETWORK_NO_SOURCE
+ m_networkState = NETWORK_NO_SOURCE;
+
+ // 2 - Asynchronously await a stable state.
+
m_playedTimeRanges = TimeRanges::create();
m_lastSeekTime = 0;
m_closedCaptionsVisible = false;
@@ -549,11 +561,7 @@ void HTMLMediaElement::loadInternal()
return;
}
- // Steps 1 - 6 were done in prepareForLoad
-
- // 7 - Invoke the media element's resource selection algorithm.
selectMediaResource();
- m_processingLoad = false;
}
void HTMLMediaElement::selectMediaResource()
@@ -561,11 +569,6 @@ void HTMLMediaElement::selectMediaResource()
enum Mode { attribute, children };
Mode mode = attribute;
- // 1 - Set the networkState to NETWORK_NO_SOURCE
- m_networkState = NETWORK_NO_SOURCE;
-
- // 2 - Asynchronously await a stable state.
-
// 3 - ... the media element has neither a src attribute ...
if (!hasAttribute(srcAttr)) {
// ... nor a source element child: ...
diff --git a/WebCore/html/HTMLMediaElement.h b/WebCore/html/HTMLMediaElement.h
index aeec188..a73abba 100644
--- a/WebCore/html/HTMLMediaElement.h
+++ b/WebCore/html/HTMLMediaElement.h
@@ -340,7 +340,6 @@ private:
bool m_playing : 1;
bool m_isWaitingUntilMediaCanStart : 1;
- bool m_processingLoad : 1;
bool m_delayingTheLoadEvent : 1;
bool m_haveFiredLoadedData : 1;
bool m_inActiveDocument : 1;
diff --git a/WebCore/html/HTMLObjectElement.cpp b/WebCore/html/HTMLObjectElement.cpp
index d4bccc3..5989ec7 100644
--- a/WebCore/html/HTMLObjectElement.cpp
+++ b/WebCore/html/HTMLObjectElement.cpp
@@ -70,11 +70,11 @@ RenderWidget* HTMLObjectElement::renderWidgetForJSBindings() const
void HTMLObjectElement::parseMappedAttribute(Attribute* attr)
{
String val = attr->value();
- int pos;
+ size_t pos;
if (attr->name() == typeAttr) {
m_serviceType = val.lower();
pos = m_serviceType.find(";");
- if (pos != -1)
+ if (pos != notFound)
m_serviceType = m_serviceType.left(pos);
if (renderer())
m_needWidgetUpdate = true;
diff --git a/WebCore/html/HTMLScriptRunner.cpp b/WebCore/html/HTMLScriptRunner.cpp
index 4a9058f..0d603ed 100644
--- a/WebCore/html/HTMLScriptRunner.cpp
+++ b/WebCore/html/HTMLScriptRunner.cpp
@@ -43,23 +43,22 @@ namespace WebCore {
using namespace HTMLNames;
-class NestScript : public Noncopyable {
+// FIXME: Factor out to avoid duplication with HTMLDocumentParser.
+class NestingLevelIncrementer : public Noncopyable {
public:
- NestScript(unsigned& nestingLevel, HTMLInputStream& inputStream)
+ explicit NestingLevelIncrementer(unsigned& nestingLevel)
: m_nestingLevel(&nestingLevel)
- , m_savedInsertionPoint(inputStream)
{
++(*m_nestingLevel);
}
- ~NestScript()
+ ~NestingLevelIncrementer()
{
--(*m_nestingLevel);
}
private:
unsigned* m_nestingLevel;
- InsertionPointRecord m_savedInsertionPoint;
};
HTMLScriptRunner::HTMLScriptRunner(Document* document, HTMLScriptRunnerHost* host)
@@ -97,7 +96,7 @@ inline PassRefPtr<Event> createScriptErrorEvent()
return Event::create(eventNames().errorEvent, true, false);
}
-ScriptSourceCode HTMLScriptRunner::sourceFromPendingScript(const PendingScript& script, bool& errorOccurred)
+ScriptSourceCode HTMLScriptRunner::sourceFromPendingScript(const PendingScript& script, bool& errorOccurred) const
{
if (script.cachedScript()) {
errorOccurred = script.cachedScript()->errorOccurred();
@@ -118,22 +117,29 @@ bool HTMLScriptRunner::isPendingScriptReady(const PendingScript& script)
return true;
}
-void HTMLScriptRunner::executePendingScript()
+void HTMLScriptRunner::executeParsingBlockingScript()
{
ASSERT(!m_scriptNestingLevel);
ASSERT(m_document->haveStylesheetsLoaded());
- bool errorOccurred = false;
ASSERT(isPendingScriptReady(m_parsingBlockingScript));
- ScriptSourceCode sourceCode = sourceFromPendingScript(m_parsingBlockingScript, errorOccurred);
// 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);
+}
+
+void HTMLScriptRunner::executePendingScriptAndDispatchEvent(PendingScript& pendingScript)
+{
+ bool errorOccurred = false;
+ ScriptSourceCode sourceCode = sourceFromPendingScript(pendingScript, errorOccurred);
+
// Clear the pending script before possible rentrancy from executeScript()
- RefPtr<Element> scriptElement = m_parsingBlockingScript.releaseElementAndClear();
+ RefPtr<Element> scriptElement = pendingScript.releaseElementAndClear();
{
- NestScript nestingLevel(m_scriptNestingLevel, m_host->inputStream());
+ NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel);
if (errorOccurred)
scriptElement->dispatchEvent(createScriptErrorEvent());
else {
@@ -144,12 +150,8 @@ void HTMLScriptRunner::executePendingScript()
ASSERT(!m_scriptNestingLevel);
}
-void HTMLScriptRunner::executeScript(Element* element, const ScriptSourceCode& sourceCode)
+void HTMLScriptRunner::executeScript(Element* element, const ScriptSourceCode& sourceCode) const
{
- // FIXME: We do not block inline <script> tags on stylesheets for now.
- // When we do, || !element->hasAttribute(srcAttr) should be removed from
- // the ASSERT below. See https://bugs.webkit.org/show_bug.cgi?id=40047
- ASSERT(m_document->haveStylesheetsLoaded() || !element->hasAttribute(srcAttr));
ScriptElement* scriptElement = toScriptElement(element);
ASSERT(scriptElement);
if (!scriptElement->shouldExecuteAsJavaScript())
@@ -204,7 +206,7 @@ bool HTMLScriptRunner::executeParsingBlockingScripts()
// We only really need to check once.
if (!isPendingScriptReady(m_parsingBlockingScript))
return false;
- executePendingScript();
+ executeParsingBlockingScript();
}
return true;
}
@@ -228,31 +230,39 @@ bool HTMLScriptRunner::executeScriptsWaitingForStylesheets()
return executeParsingBlockingScripts();
}
-void HTMLScriptRunner::requestScript(Element* script)
+void HTMLScriptRunner::requestParsingBlockingScript(Element* element)
{
- ASSERT(!m_parsingBlockingScript.element());
- AtomicString srcValue = script->getAttribute(srcAttr);
+ if (!requestPendingScript(m_parsingBlockingScript, element))
+ return;
+
+ ASSERT(m_parsingBlockingScript.cachedScript());
+
+ // We only care about a load callback if cachedScript is not already
+ // in the cache. Callers will attempt to run the m_parsingBlockingScript
+ // if possible before returning control to the parser.
+ if (!m_parsingBlockingScript.cachedScript()->isLoaded())
+ watchForLoad(m_parsingBlockingScript);
+}
+
+bool HTMLScriptRunner::requestPendingScript(PendingScript& pendingScript, Element* script) const
+{
+ ASSERT(!pendingScript.element());
+ const AtomicString& srcValue = script->getAttribute(srcAttr);
// Allow the host to disllow script loads (using the XSSAuditor, etc.)
if (!m_host->shouldLoadExternalScriptFromSrc(srcValue))
- return;
+ return false;
// FIXME: We need to resolve the url relative to the element.
if (!script->dispatchBeforeLoadEvent(srcValue))
- return;
- m_parsingBlockingScript.adoptElement(script);
+ 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());
if (!cachedScript) {
notImplemented(); // Dispatch error event.
- return;
+ return false;
}
-
- m_parsingBlockingScript.setCachedScript(cachedScript);
-
- // We only care about a load callback if cachedScript is not already
- // in the cache. Callers will attempt to run the m_parsingBlockingScript
- // if possible before returning control to the parser.
- if (!m_parsingBlockingScript.cachedScript()->isLoaded())
- watchForLoad(m_parsingBlockingScript);
+ pendingScript.setCachedScript(cachedScript);
+ return true;
}
// This method is meant to match the HTML5 definition of "running a script"
@@ -261,17 +271,21 @@ void HTMLScriptRunner::runScript(Element* script, int startingLineNumber)
{
ASSERT(!haveParsingBlockingScript());
{
- NestScript nestingLevel(m_scriptNestingLevel, m_host->inputStream());
+ InsertionPointRecord insertionPointRecord(m_host->inputStream());
+ NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel);
// Check script type and language, current code uses ScriptElement::shouldExecuteAsJavaScript(), but that may not be HTML5 compliant.
notImplemented(); // event for support
if (script->hasAttribute(srcAttr)) {
// FIXME: Handle defer and async
- requestScript(script);
+ requestParsingBlockingScript(script);
} else {
// FIXME: We do not block inline <script> tags on stylesheets to match the
- // old parser for now. See https://bugs.webkit.org/show_bug.cgi?id=40047
+ // old parser for now. When we do, the ASSERT below should be added.
+ // See https://bugs.webkit.org/show_bug.cgi?id=40047
+ // ASSERT(document()->haveStylesheetsLoaded());
+ ASSERT(isExecutingScript());
ScriptSourceCode sourceCode(script->textContent(), documentURLForScriptExecution(m_document), startingLineNumber);
executeScript(script, sourceCode);
}
diff --git a/WebCore/html/HTMLScriptRunner.h b/WebCore/html/HTMLScriptRunner.h
index 85801b2..981d433 100644
--- a/WebCore/html/HTMLScriptRunner.h
+++ b/WebCore/html/HTMLScriptRunner.h
@@ -52,25 +52,27 @@ public:
bool hasScriptsWaitingForStylesheets() const { return m_hasScriptsWaitingForStylesheets; }
bool executeScriptsWaitingForStylesheets();
- bool isExecutingScript() { return !!m_scriptNestingLevel; }
+ bool isExecutingScript() const { return !!m_scriptNestingLevel; }
private:
Frame* frame() const;
+ void executeParsingBlockingScript();
+ void executePendingScriptAndDispatchEvent(PendingScript&);
+ void executeScript(Element*, const ScriptSourceCode&) const;
bool haveParsingBlockingScript() const;
bool executeParsingBlockingScripts();
- void executePendingScript();
- void requestScript(Element*);
+ void requestParsingBlockingScript(Element*);
+ bool requestPendingScript(PendingScript&, Element*) const;
+
void runScript(Element*, int startingLineNumber);
// Helpers for dealing with HTMLScriptRunnerHost
void watchForLoad(PendingScript&);
void stopWatchingForLoad(PendingScript&);
- void executeScript(Element*, const ScriptSourceCode&);
-
bool isPendingScriptReady(const PendingScript&);
- ScriptSourceCode sourceFromPendingScript(const PendingScript&, bool& errorOccurred);
+ ScriptSourceCode sourceFromPendingScript(const PendingScript&, bool& errorOccurred) const;
Document* m_document;
HTMLScriptRunnerHost* m_host;
diff --git a/WebCore/html/HTMLSourceElement.cpp b/WebCore/html/HTMLSourceElement.cpp
index 6c26610..96c9829 100644
--- a/WebCore/html/HTMLSourceElement.cpp
+++ b/WebCore/html/HTMLSourceElement.cpp
@@ -52,9 +52,9 @@ PassRefPtr<HTMLSourceElement> HTMLSourceElement::create(const QualifiedName& tag
return adoptRef(new HTMLSourceElement(tagName, document));
}
-void HTMLSourceElement::insertedIntoDocument()
+void HTMLSourceElement::insertedIntoTree(bool deep)
{
- HTMLElement::insertedIntoDocument();
+ HTMLElement::insertedIntoTree(deep);
if (parentNode() && (parentNode()->hasTagName(audioTag) || parentNode()->hasTagName(videoTag))) {
HTMLMediaElement* media = static_cast<HTMLMediaElement*>(parentNode());
if (media->networkState() == HTMLMediaElement::NETWORK_EMPTY)
diff --git a/WebCore/html/HTMLSourceElement.h b/WebCore/html/HTMLSourceElement.h
index 20049cc..7d49a3e 100644
--- a/WebCore/html/HTMLSourceElement.h
+++ b/WebCore/html/HTMLSourceElement.h
@@ -52,7 +52,7 @@ private:
virtual HTMLTagStatus endTagRequirement() const { return TagStatusForbidden; }
virtual int tagPriority() const { return 0; }
- virtual void insertedIntoDocument();
+ virtual void insertedIntoTree(bool);
virtual bool isURLAttribute(Attribute*) const;
void errorEventTimerFired(Timer<HTMLSourceElement>*);
diff --git a/WebCore/html/HTMLToken.h b/WebCore/html/HTMLToken.h
index 5f2869b..e42a829 100644
--- a/WebCore/html/HTMLToken.h
+++ b/WebCore/html/HTMLToken.h
@@ -45,8 +45,16 @@ public:
EndOfFile,
};
+ class Range {
+ public:
+ int m_start;
+ int m_end;
+ };
+
class Attribute {
public:
+ Range m_nameRange;
+ Range m_valueRange;
WTF::Vector<UChar, 32> m_name;
WTF::Vector<UChar, 32> m_value;
};
@@ -56,12 +64,22 @@ public:
HTMLToken() { clear(); }
- void clear()
+ void clear(int startIndex = 0)
{
m_type = Uninitialized;
+ m_range.m_start = startIndex;
+ m_range.m_end = startIndex;
m_data.clear();
}
+ int startIndex() const { return m_range.m_start; }
+ int endIndex() const { return m_range.m_end; }
+
+ void end(int endIndex)
+ {
+ m_range.m_end = endIndex;
+ }
+
void makeEndOfFile()
{
ASSERT(m_type == Uninitialized);
@@ -146,12 +164,44 @@ public:
ASSERT(m_type == StartTag || m_type == EndTag);
m_attributes.grow(m_attributes.size() + 1);
m_currentAttribute = &m_attributes.last();
+#ifndef NDEBUG
+ m_currentAttribute->m_nameRange.m_start = 0;
+ m_currentAttribute->m_nameRange.m_end = 0;
+ m_currentAttribute->m_valueRange.m_start = 0;
+ m_currentAttribute->m_valueRange.m_end = 0;
+#endif
+ }
+
+ void beginAttributeName(int index)
+ {
+ m_currentAttribute->m_nameRange.m_start = index;
+ }
+
+ void endAttributeName(int index)
+ {
+ m_currentAttribute->m_nameRange.m_end = index;
+ m_currentAttribute->m_valueRange.m_start = index;
+ m_currentAttribute->m_valueRange.m_end = index;
+ }
+
+ void beginAttributeValue(int index)
+ {
+ m_currentAttribute->m_valueRange.m_start = index;
+#ifndef NDEBUG
+ m_currentAttribute->m_valueRange.m_end = 0;
+#endif
+ }
+
+ void endAttributeValue(int index)
+ {
+ m_currentAttribute->m_valueRange.m_end = index;
}
void appendToAttributeName(UChar character)
{
ASSERT(character);
ASSERT(m_type == StartTag || m_type == EndTag);
+ ASSERT(m_currentAttribute->m_nameRange.m_start);
m_currentAttribute->m_name.append(character);
}
@@ -159,6 +209,7 @@ public:
{
ASSERT(character);
ASSERT(m_type == StartTag || m_type == EndTag);
+ ASSERT(m_currentAttribute->m_valueRange.m_start);
m_currentAttribute->m_value.append(character);
}
@@ -280,6 +331,9 @@ private:
Type m_type;
+ // Which characters from the input stream are represented by this token.
+ Range m_range;
+
// "name" for DOCTYPE, StartTag, and EndTag
// "characters" for Character
// "data" for Comment
@@ -323,6 +377,10 @@ public:
if (!iter->m_name.isEmpty()) {
String name(iter->m_name.data(), iter->m_name.size());
String value(iter->m_value.data(), iter->m_value.size());
+ ASSERT(iter->m_nameRange.m_start);
+ ASSERT(iter->m_nameRange.m_end);
+ ASSERT(iter->m_valueRange.m_start);
+ ASSERT(iter->m_valueRange.m_end);
RefPtr<Attribute> mappedAttribute = Attribute::createMapped(name, value);
if (!m_attributes) {
m_attributes = NamedNodeMap::create();
diff --git a/WebCore/html/HTMLTokenizer.cpp b/WebCore/html/HTMLTokenizer.cpp
index a52aba6..a18701a 100644
--- a/WebCore/html/HTMLTokenizer.cpp
+++ b/WebCore/html/HTMLTokenizer.cpp
@@ -28,7 +28,6 @@
#include "config.h"
#include "HTMLTokenizer.h"
-#include "AtomicString.h"
#include "HTMLEntityParser.h"
#include "HTMLToken.h"
#include "HTMLNames.h"
@@ -36,6 +35,7 @@
#include <wtf/ASCIICType.h>
#include <wtf/CurrentTime.h>
#include <wtf/UnusedParam.h>
+#include <wtf/text/AtomicString.h>
#include <wtf/text/CString.h>
#include <wtf/unicode/Unicode.h>
@@ -152,7 +152,7 @@ inline bool HTMLTokenizer::processEntity(SegmentedString& source)
do { \
m_state = stateName; \
if (!m_inputStreamPreprocessor.advance(source, m_lineNumber)) \
- return shouldEmitBufferedCharacterToken(source); \
+ return haveBufferedCharacterToken(); \
cc = m_inputStreamPreprocessor.nextInputCharacter(); \
goto stateName; \
} while (false)
@@ -165,7 +165,7 @@ inline bool HTMLTokenizer::processEntity(SegmentedString& source)
do { \
m_state = stateName; \
if (source.isEmpty() || !m_inputStreamPreprocessor.peek(source, m_lineNumber)) \
- return shouldEmitBufferedCharacterToken(source); \
+ return haveBufferedCharacterToken(); \
cc = m_inputStreamPreprocessor.nextInputCharacter(); \
goto stateName; \
} while (false)
@@ -202,7 +202,7 @@ bool HTMLTokenizer::emitAndReconsumeIn(SegmentedString&, State state)
// Check if we have buffered characters to emit first before emitting the EOF.
bool HTMLTokenizer::emitEndOfFile(SegmentedString& source)
{
- if (shouldEmitBufferedCharacterToken(source))
+ if (haveBufferedCharacterToken())
return true;
m_state = DataState;
source.advance(m_lineNumber);
@@ -229,7 +229,7 @@ bool HTMLTokenizer::flushBufferedEndTag(SegmentedString& source)
return true; \
if (source.isEmpty() \
|| !m_inputStreamPreprocessor.peek(source, m_lineNumber)) \
- return shouldEmitBufferedCharacterToken(source); \
+ return haveBufferedCharacterToken(); \
cc = m_inputStreamPreprocessor.nextInputCharacter(); \
goto stateName; \
} while (false)
@@ -260,7 +260,7 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
}
if (source.isEmpty() || !m_inputStreamPreprocessor.peek(source, m_lineNumber))
- return shouldEmitBufferedCharacterToken(source);
+ return haveBufferedCharacterToken();
UChar cc = m_inputStreamPreprocessor.nextInputCharacter();
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody
@@ -308,7 +308,7 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
BEGIN_STATE(CharacterReferenceInDataState) {
if (!processEntity(source))
- return shouldEmitBufferedCharacterToken(source);
+ return haveBufferedCharacterToken();
SWITCH_TO(DataState);
}
END_STATE()
@@ -329,7 +329,7 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
BEGIN_STATE(CharacterReferenceInRCDATAState) {
if (!processEntity(source))
- return shouldEmitBufferedCharacterToken(source);
+ return haveBufferedCharacterToken();
SWITCH_TO(RCDATAState);
}
END_STATE()
@@ -864,6 +864,7 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
return emitAndResumeIn(source, DataState);
else if (isASCIIUpper(cc)) {
m_token->addNewAttribute();
+ m_token->beginAttributeName(source.numberOfCharactersConsumed());
m_token->appendToAttributeName(toLowerCase(cc));
ADVANCE_TO(AttributeNameState);
} else if (cc == InputStreamPreprocessor::endOfFileMarker) {
@@ -873,6 +874,7 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
if (cc == '"' || cc == '\'' || cc == '<' || cc == '=')
parseError();
m_token->addNewAttribute();
+ m_token->beginAttributeName(source.numberOfCharactersConsumed());
m_token->appendToAttributeName(cc);
ADVANCE_TO(AttributeNameState);
}
@@ -880,19 +882,24 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
END_STATE()
BEGIN_STATE(AttributeNameState) {
- if (isTokenizerWhitespace(cc))
+ if (isTokenizerWhitespace(cc)) {
+ m_token->endAttributeName(source.numberOfCharactersConsumed());
ADVANCE_TO(AfterAttributeNameState);
- else if (cc == '/')
+ } else if (cc == '/') {
+ m_token->endAttributeName(source.numberOfCharactersConsumed());
ADVANCE_TO(SelfClosingStartTagState);
- else if (cc == '=')
+ } else if (cc == '=') {
+ m_token->endAttributeName(source.numberOfCharactersConsumed());
ADVANCE_TO(BeforeAttributeValueState);
- else if (cc == '>')
+ } else if (cc == '>') {
+ m_token->endAttributeName(source.numberOfCharactersConsumed());
return emitAndResumeIn(source, DataState);
- else if (isASCIIUpper(cc)) {
+ } else if (isASCIIUpper(cc)) {
m_token->appendToAttributeName(toLowerCase(cc));
ADVANCE_TO(AttributeNameState);
} else if (cc == InputStreamPreprocessor::endOfFileMarker) {
parseError();
+ m_token->endAttributeName(source.numberOfCharactersConsumed());
RECONSUME_IN(DataState);
} else {
if (cc == '"' || cc == '\'' || cc == '<' || cc == '=')
@@ -914,6 +921,7 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
return emitAndResumeIn(source, DataState);
else if (isASCIIUpper(cc)) {
m_token->addNewAttribute();
+ m_token->beginAttributeName(source.numberOfCharactersConsumed());
m_token->appendToAttributeName(toLowerCase(cc));
ADVANCE_TO(AttributeNameState);
} else if (cc == InputStreamPreprocessor::endOfFileMarker) {
@@ -923,6 +931,7 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
if (cc == '"' || cc == '\'' || cc == '<')
parseError();
m_token->addNewAttribute();
+ m_token->beginAttributeName(source.numberOfCharactersConsumed());
m_token->appendToAttributeName(cc);
ADVANCE_TO(AttributeNameState);
}
@@ -932,13 +941,16 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
BEGIN_STATE(BeforeAttributeValueState) {
if (isTokenizerWhitespace(cc))
ADVANCE_TO(BeforeAttributeValueState);
- else if (cc == '"')
+ else if (cc == '"') {
+ m_token->beginAttributeValue(source.numberOfCharactersConsumed() + 1);
ADVANCE_TO(AttributeValueDoubleQuotedState);
- else if (cc == '&')
+ } else if (cc == '&') {
+ m_token->beginAttributeValue(source.numberOfCharactersConsumed());
RECONSUME_IN(AttributeValueUnquotedState);
- else if (cc == '\'')
+ } else if (cc == '\'') {
+ m_token->beginAttributeValue(source.numberOfCharactersConsumed() + 1);
ADVANCE_TO(AttributeValueSingleQuotedState);
- else if (cc == '>') {
+ } else if (cc == '>') {
parseError();
return emitAndResumeIn(source, DataState);
} else if (cc == InputStreamPreprocessor::endOfFileMarker) {
@@ -947,6 +959,7 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
} else {
if (cc == '<' || cc == '=' || cc == '`')
parseError();
+ m_token->beginAttributeValue(source.numberOfCharactersConsumed());
m_token->appendToAttributeValue(cc);
ADVANCE_TO(AttributeValueUnquotedState);
}
@@ -954,13 +967,15 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
END_STATE()
BEGIN_STATE(AttributeValueDoubleQuotedState) {
- if (cc == '"')
+ if (cc == '"') {
+ m_token->endAttributeValue(source.numberOfCharactersConsumed());
ADVANCE_TO(AfterAttributeValueQuotedState);
- else if (cc == '&') {
+ } else if (cc == '&') {
m_additionalAllowedCharacter = '"';
ADVANCE_TO(CharacterReferenceInAttributeValueState);
} else if (cc == InputStreamPreprocessor::endOfFileMarker) {
parseError();
+ m_token->endAttributeValue(source.numberOfCharactersConsumed());
RECONSUME_IN(DataState);
} else {
m_token->appendToAttributeValue(cc);
@@ -970,13 +985,15 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
END_STATE()
BEGIN_STATE(AttributeValueSingleQuotedState) {
- if (cc == '\'')
+ if (cc == '\'') {
+ m_token->endAttributeValue(source.numberOfCharactersConsumed());
ADVANCE_TO(AfterAttributeValueQuotedState);
- else if (cc == '&') {
+ } else if (cc == '&') {
m_additionalAllowedCharacter = '\'';
ADVANCE_TO(CharacterReferenceInAttributeValueState);
} else if (cc == InputStreamPreprocessor::endOfFileMarker) {
parseError();
+ m_token->endAttributeValue(source.numberOfCharactersConsumed());
RECONSUME_IN(DataState);
} else {
m_token->appendToAttributeValue(cc);
@@ -986,15 +1003,18 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
END_STATE()
BEGIN_STATE(AttributeValueUnquotedState) {
- if (isTokenizerWhitespace(cc))
+ if (isTokenizerWhitespace(cc)) {
+ m_token->endAttributeValue(source.numberOfCharactersConsumed());
ADVANCE_TO(BeforeAttributeNameState);
- else if (cc == '&') {
+ } else if (cc == '&') {
m_additionalAllowedCharacter = '>';
ADVANCE_TO(CharacterReferenceInAttributeValueState);
- } else if (cc == '>')
+ } else if (cc == '>') {
+ m_token->endAttributeValue(source.numberOfCharactersConsumed());
return emitAndResumeIn(source, DataState);
- else if (cc == InputStreamPreprocessor::endOfFileMarker) {
+ } else if (cc == InputStreamPreprocessor::endOfFileMarker) {
parseError();
+ m_token->endAttributeValue(source.numberOfCharactersConsumed());
RECONSUME_IN(DataState);
} else {
if (cc == '"' || cc == '\'' || cc == '<' || cc == '=' || cc == '`')
@@ -1009,7 +1029,7 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
bool notEnoughCharacters = false;
unsigned value = consumeHTMLEntity(source, notEnoughCharacters, m_additionalAllowedCharacter);
if (notEnoughCharacters)
- return shouldEmitBufferedCharacterToken(source);
+ return haveBufferedCharacterToken();
if (!value)
m_token->appendToAttributeValue('&');
else if (value < 0xFFFF)
@@ -1093,14 +1113,14 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
m_token->beginComment();
SWITCH_TO(CommentStartState);
} else if (result == SegmentedString::NotEnoughCharacters)
- return shouldEmitBufferedCharacterToken(source);
+ return haveBufferedCharacterToken();
} else if (cc == 'D' || cc == 'd') {
SegmentedString::LookAheadResult result = source.lookAheadIgnoringCase(doctypeString);
if (result == SegmentedString::DidMatch) {
advanceStringAndASSERTIgnoringCase(source, "doctype");
SWITCH_TO(DOCTYPEState);
} else if (result == SegmentedString::NotEnoughCharacters)
- return shouldEmitBufferedCharacterToken(source);
+ return haveBufferedCharacterToken();
}
notImplemented();
// FIXME: We're still missing the bits about the insertion mode being in foreign content:
@@ -1313,14 +1333,14 @@ bool HTMLTokenizer::nextToken(SegmentedString& source, HTMLToken& token)
advanceStringAndASSERTIgnoringCase(source, "public");
SWITCH_TO(AfterDOCTYPEPublicKeywordState);
} else if (result == SegmentedString::NotEnoughCharacters)
- return shouldEmitBufferedCharacterToken(source);
+ return haveBufferedCharacterToken();
} else if (cc == 'S' || cc == 's') {
SegmentedString::LookAheadResult result = source.lookAheadIgnoringCase(systemString);
if (result == SegmentedString::DidMatch) {
advanceStringAndASSERTIgnoringCase(source, "system");
SWITCH_TO(AfterDOCTYPESystemKeywordState);
} else if (result == SegmentedString::NotEnoughCharacters)
- return shouldEmitBufferedCharacterToken(source);
+ return haveBufferedCharacterToken();
}
parseError();
m_token->setForceQuirks();
@@ -1629,10 +1649,9 @@ inline void HTMLTokenizer::parseError()
notImplemented();
}
-inline bool HTMLTokenizer::shouldEmitBufferedCharacterToken(const SegmentedString& source)
+inline bool HTMLTokenizer::haveBufferedCharacterToken()
{
- return source.isClosed() && m_token->type() == HTMLToken::Character;
+ return m_token->type() == HTMLToken::Character;
}
}
-
diff --git a/WebCore/html/HTMLTokenizer.h b/WebCore/html/HTMLTokenizer.h
index 0e9ba3a..6fb3053 100644
--- a/WebCore/html/HTMLTokenizer.h
+++ b/WebCore/html/HTMLTokenizer.h
@@ -27,10 +27,10 @@
#ifndef HTMLTokenizer_h
#define HTMLTokenizer_h
-#include "AtomicString.h"
#include "SegmentedString.h"
#include <wtf/Noncopyable.h>
#include <wtf/Vector.h>
+#include <wtf/text/AtomicString.h>
namespace WebCore {
@@ -254,7 +254,7 @@ private:
inline void saveEndTagNameIfNeeded();
inline bool isAppropriateEndTag();
- inline bool shouldEmitBufferedCharacterToken(const SegmentedString&);
+ inline bool haveBufferedCharacterToken();
State m_state;
diff --git a/WebCore/html/HTMLTreeBuilder.cpp b/WebCore/html/HTMLTreeBuilder.cpp
index 2c7d40d..fd0b62e 100644
--- a/WebCore/html/HTMLTreeBuilder.cpp
+++ b/WebCore/html/HTMLTreeBuilder.cpp
@@ -39,7 +39,6 @@
#include "HTMLScriptElement.h"
#include "HTMLToken.h"
#include "HTMLTokenizer.h"
-#include "LegacyHTMLDocumentParser.h"
#include "LegacyHTMLTreeBuilder.h"
#include "LocalizedStrings.h"
#include "MathMLNames.h"
@@ -67,6 +66,11 @@ inline bool isTreeBuilderWhitepace(UChar c)
return c == '\t' || c == '\x0A' || c == '\x0C' || c == '\x0D' || c == ' ';
}
+inline bool isNotTreeBuilderWhitepace(UChar c)
+{
+ return !isTreeBuilderWhitepace(c);
+}
+
inline bool isTreeBuilderWhitepaceOrReplacementCharacter(UChar c)
{
return isTreeBuilderWhitepace(c) || c == 0xFFFD;
@@ -303,21 +307,17 @@ public:
void skipLeadingWhitespace()
{
- ASSERT(!isEmpty());
- while (isTreeBuilderWhitepace(*m_current)) {
- if (++m_current == m_end)
- return;
- }
+ skipLeading<isTreeBuilderWhitepace>();
}
String takeLeadingWhitespace()
{
- ASSERT(!isEmpty());
- const UChar* start = m_current;
- skipLeadingWhitespace();
- if (start == m_current)
- return String();
- return String(start, m_current - start);
+ return takeLeading<isTreeBuilderWhitepace>();
+ }
+
+ String takeLeadingNonWhitespace()
+ {
+ return takeLeading<isNotTreeBuilderWhitepace>();
}
String takeRemaining()
@@ -352,6 +352,27 @@ public:
}
private:
+ template<bool characterPredicate(UChar)>
+ void skipLeading()
+ {
+ ASSERT(!isEmpty());
+ while (characterPredicate(*m_current)) {
+ if (++m_current == m_end)
+ return;
+ }
+ }
+
+ template<bool characterPredicate(UChar)>
+ String takeLeading()
+ {
+ ASSERT(!isEmpty());
+ const UChar* start = m_current;
+ skipLeading<characterPredicate>();
+ if (start == m_current)
+ return String();
+ return String(start, m_current - start);
+ }
+
const UChar* m_current;
const UChar* m_end;
};
@@ -391,13 +412,14 @@ HTMLTreeBuilder::HTMLTreeBuilder(HTMLTokenizer* tokenizer, DocumentFragment* fra
{
if (shouldUseLegacyTreeBuilder(fragment->document()))
return;
- // This is steps 2-6 of the HTML5 Fragment Case parsing algorithm:
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case
- if (contextElement)
+ if (contextElement) {
+ // Steps 4.2-4.6 of the HTML5 Fragment Case parsing algorithm:
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case
m_document->setParseMode(contextElement->document()->parseMode());
- processFakeStartTag(htmlTag);
- resetInsertionModeAppropriately();
- m_tree.setForm(closestFormAncestor(contextElement));
+ processFakeStartTag(htmlTag);
+ resetInsertionModeAppropriately();
+ m_tree.setForm(closestFormAncestor(contextElement));
+ }
}
HTMLTreeBuilder::~HTMLTreeBuilder()
@@ -1997,7 +2019,9 @@ void HTMLTreeBuilder::processEndTagForInCell(AtomicHTMLToken& token)
m_tree.openElements()->popUntilPopped(token.name());
m_tree.activeFormattingElements()->clearToLastMarker();
setInsertionMode(InRowMode);
- ASSERT(m_tree.currentElement()->hasTagName(trTag));
+ // FIXME: The fragment case of this ASSERT is a spec bug:
+ // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10338
+ ASSERT(m_tree.currentElement()->hasTagName(trTag) || (isParsingFragment() && m_fragmentContext.contextElement()->hasTagName(trTag)));
return;
}
if (token.name() == bodyTag
@@ -2628,7 +2652,10 @@ ReprocessBuffer:
return;
if (!processColgroupEndTagForInColumnGroup()) {
ASSERT(isParsingFragment());
- return;
+ // The spec tells us to drop these characters on the floor.
+ buffer.takeLeadingNonWhitespace();
+ if (buffer.isEmpty())
+ return;
}
goto ReprocessBuffer;
}
diff --git a/WebCore/html/HTMLViewSourceDocument.cpp b/WebCore/html/HTMLViewSourceDocument.cpp
index e1b959b..e0e71ee 100644
--- a/WebCore/html/HTMLViewSourceDocument.cpp
+++ b/WebCore/html/HTMLViewSourceDocument.cpp
@@ -36,7 +36,9 @@
#include "HTMLTableElement.h"
#include "HTMLTableRowElement.h"
#include "HTMLTableSectionElement.h"
-#include "LegacyHTMLDocumentParser.h"
+#include "HTMLToken.h"
+#include "HTMLViewSourceParser.h"
+#include "SegmentedString.h"
#include "Text.h"
#include "TextDocument.h"
@@ -53,15 +55,13 @@ HTMLViewSourceDocument::HTMLViewSourceDocument(Frame* frame, const KURL& url, co
DocumentParser* HTMLViewSourceDocument::createParser()
{
- // Use LegacyHTMLDocumentParser if applicable, otherwise use TextDocumentParser.
+ // 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"
#endif
- ) {
- // FIXME: Should respect Settings::html5ParserEnabled()
- return new LegacyHTMLDocumentParser(this);
- }
+ )
+ return new HTMLViewSourceParser(this);
return createTextDocumentParser(this);
}
@@ -100,107 +100,91 @@ void HTMLViewSourceDocument::addViewSourceText(const String& text)
addText(text, "");
}
-void HTMLViewSourceDocument::addViewSourceToken(Token* token)
+void HTMLViewSourceDocument::addSource(const String& source, HTMLToken& token)
{
if (!m_current)
createContainingTable();
- if (token->tagName == textAtom)
- addText(token->text.get(), "");
- else if (token->tagName == commentAtom) {
- if (token->beginTag) {
- m_current = addSpanWithClassName("webkit-html-comment");
- addText(String("<!--") + token->text.get() + "-->", "webkit-html-comment");
- }
- } else {
- // Handle the tag.
- String classNameStr = "webkit-html-tag";
- m_current = addSpanWithClassName(classNameStr);
-
- String text = "<";
- if (!token->beginTag)
- text += "/";
- text += token->tagName;
- Vector<UChar>* guide = token->m_sourceInfo.get();
- if (!guide || !guide->size())
- text += ">";
-
- addText(text, classNameStr);
-
- // Walk our guide string that tells us where attribute names/values should go.
- if (guide && guide->size()) {
- unsigned size = guide->size();
- unsigned begin = 0;
- unsigned currAttr = 0;
- RefPtr<Attribute> attr = 0;
- for (unsigned i = 0; i < size; i++) {
- if (guide->at(i) == 'a' || guide->at(i) == 'x' || guide->at(i) == 'v') {
- // Add in the string.
- addText(String(static_cast<UChar*>(guide->data()) + begin, i - begin), classNameStr);
-
- begin = i + 1;
-
- if (guide->at(i) == 'a') {
- if (token->attrs && currAttr < token->attrs->length())
- attr = token->attrs->attributeItem(currAttr++);
- else
- attr = 0;
- }
- if (attr) {
- if (guide->at(i) == 'a') {
- String name = attr->name().toString();
-
- m_current = addSpanWithClassName("webkit-html-attribute-name");
- addText(name, "webkit-html-attribute-name");
- if (m_current != m_tbody)
- m_current = static_cast<Element*>(m_current->parent());
- } else {
- const String& value = attr->value().string();
-
- // Compare ignoring case since LegacyHTMLDocumentParser doesn't
- // lower names when passing in tokens to
- // HTMLViewSourceDocument.
- if (equalIgnoringCase(token->tagName, "base") && equalIgnoringCase(attr->name().localName(), "href")) {
- // Catch the href attribute in the base element.
- // It will be used for rendering anchors created
- // by addLink() below.
- setBaseElementURL(KURL(url(), value));
- }
-
- // FIXME: XML could use namespace prefixes and confuse us.
- if (equalIgnoringCase(attr->name().localName(), "src") || equalIgnoringCase(attr->name().localName(), "href"))
- m_current = addLink(value, equalIgnoringCase(token->tagName, "a"));
- else
- m_current = addSpanWithClassName("webkit-html-attribute-value");
- addText(value, "webkit-html-attribute-value");
- if (m_current != m_tbody)
- m_current = static_cast<Element*>(m_current->parent());
- }
- }
- }
- }
-
- // Add in any string that might be left.
- if (begin < size)
- addText(String(static_cast<UChar*>(guide->data()) + begin, size - begin), classNameStr);
-
- // Add in the end tag.
- addText(">", classNameStr);
- }
-
- m_current = m_td;
+ switch (token.type()) {
+ case HTMLToken::Uninitialized:
+ ASSERT_NOT_REACHED();
+ break;
+ case HTMLToken::DOCTYPE:
+ processDoctypeToken(source, token);
+ break;
+ case HTMLToken::EndOfFile:
+ break;
+ case HTMLToken::StartTag:
+ case HTMLToken::EndTag:
+ processTagToken(source, token);
+ break;
+ case HTMLToken::Comment:
+ processCommentToken(source, token);
+ break;
+ case HTMLToken::Character:
+ processCharacterToken(source, token);
+ break;
}
}
-void HTMLViewSourceDocument::addViewSourceDoctypeToken(DoctypeToken* doctypeToken)
+void HTMLViewSourceDocument::processDoctypeToken(const String& source, HTMLToken&)
{
if (!m_current)
createContainingTable();
m_current = addSpanWithClassName("webkit-html-doctype");
- String text = "<";
- text += String::adopt(doctypeToken->m_source);
- text += ">";
- addText(text, "webkit-html-doctype");
+ addText(source, "webkit-html-doctype");
+ m_current = m_td;
+}
+
+void HTMLViewSourceDocument::processTagToken(const String& source, HTMLToken& token)
+{
+ String classNameStr = "webkit-html-tag";
+ m_current = addSpanWithClassName(classNameStr);
+
+ AtomicString tagName(token.name().data(), token.name().size());
+
+ unsigned index = 0;
+ HTMLToken::AttributeList::const_iterator iter = token.attributes().begin();
+ while (index < source.length()) {
+ if (iter == token.attributes().end()) {
+ // We want to show the remaining characters in the token.
+ index = addRange(source, index, source.length(), "");
+ ASSERT(index == source.length());
+ break;
+ }
+
+ AtomicString name(iter->m_name.data(), iter->m_name.size());
+ String value(iter->m_value.data(), iter->m_value.size());
+
+ index = addRange(source, index, iter->m_nameRange.m_start - token.startIndex(), "");
+ index = addRange(source, index, iter->m_nameRange.m_end - token.startIndex(), "webkit-html-attribute-name");
+
+ if (tagName == baseTag && name == hrefAttr) {
+ // Catch the href attribute in the base element. It will be used
+ // for rendering anchors created by addLink() below.
+ setBaseElementURL(KURL(url(), value));
+ }
+
+ index = addRange(source, index, iter->m_valueRange.m_start - token.startIndex(), "");
+
+ bool isLink = name == srcAttr || name == hrefAttr;
+ index = addRange(source, index, iter->m_valueRange.m_end - token.startIndex(), "webkit-html-attribute-value", isLink, tagName == aTag);
+
+ ++iter;
+ }
+ m_current = m_td;
+}
+
+void HTMLViewSourceDocument::processCommentToken(const String& source, HTMLToken&)
+{
+ m_current = addSpanWithClassName("webkit-html-comment");
+ addText(source, "webkit-html-comment");
+ m_current = m_td;
+}
+
+void HTMLViewSourceDocument::processCharacterToken(const String& source, HTMLToken&)
+{
+ addText(source, "");
}
PassRefPtr<Element> HTMLViewSourceDocument::addSpanWithClassName(const String& className)
@@ -287,6 +271,25 @@ void HTMLViewSourceDocument::addText(const String& text, const String& className
m_current = m_tbody;
}
+int HTMLViewSourceDocument::addRange(const String& source, int start, int end, const String& className, bool isLink, bool isAnchor)
+{
+ ASSERT(start <= end);
+ if (start == end)
+ return start;
+
+ String text = source.substring(start, end - start);
+ if (!className.isEmpty()) {
+ if (isLink)
+ m_current = addLink(text, isAnchor);
+ else
+ m_current = addSpanWithClassName(className);
+ }
+ addText(text, className);
+ if (!className.isEmpty() && m_current != m_tbody)
+ m_current = static_cast<Element*>(m_current->parent());
+ return end;
+}
+
PassRefPtr<Element> HTMLViewSourceDocument::addLink(const String& url, bool isAnchor)
{
if (m_current == m_tbody)
diff --git a/WebCore/html/HTMLViewSourceDocument.h b/WebCore/html/HTMLViewSourceDocument.h
index cf6cfc1..8805848 100644
--- a/WebCore/html/HTMLViewSourceDocument.h
+++ b/WebCore/html/HTMLViewSourceDocument.h
@@ -29,11 +29,9 @@
namespace WebCore {
-class DoctypeToken;
class HTMLTableCellElement;
class HTMLTableSectionElement;
-
-struct Token;
+class HTMLToken;
class HTMLViewSourceDocument : public HTMLDocument {
public:
@@ -42,20 +40,27 @@ public:
return adoptRef(new HTMLViewSourceDocument(frame, url, mimeType));
}
- void addViewSourceToken(Token*); // Used by the LegacyHTMLDocumentParser.
+ void addSource(const String&, HTMLToken&);
+
+ void addViewSourceToken(HTMLToken&); // Used by the HTMLDocumentParser.
void addViewSourceText(const String&); // Used by the TextDocumentParser.
- void addViewSourceDoctypeToken(DoctypeToken*);
private:
HTMLViewSourceDocument(Frame*, const KURL&, const String& mimeType);
- // Returns LegacyHTMLDocumentParser or TextDocumentParser based on m_type.
+ // Returns HTMLViewSourceParser or TextDocumentParser based on m_type.
virtual DocumentParser* createParser();
+ void processDoctypeToken(const String& source, HTMLToken&);
+ void processTagToken(const String& source, HTMLToken&);
+ void processCommentToken(const String& source, HTMLToken&);
+ void processCharacterToken(const String& source, HTMLToken&);
+
void createContainingTable();
PassRefPtr<Element> addSpanWithClassName(const String&);
void addLine(const String& className);
void addText(const String& text, const String& className);
+ int addRange(const String& source, int start, int end, const String& className, bool isLink = false, bool isAnchor = false);
PassRefPtr<Element> addLink(const String& url, bool isAnchor);
String m_type;
diff --git a/WebCore/html/HTMLViewSourceParser.cpp b/WebCore/html/HTMLViewSourceParser.cpp
new file mode 100644
index 0000000..3da4c23
--- /dev/null
+++ b/WebCore/html/HTMLViewSourceParser.cpp
@@ -0,0 +1,106 @@
+/*
+ * 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 "HTMLViewSourceParser.h"
+
+#include "HTMLNames.h"
+#include "HTMLTreeBuilder.h"
+#include "HTMLViewSourceDocument.h"
+
+namespace WebCore {
+
+HTMLViewSourceParser::~HTMLViewSourceParser()
+{
+}
+
+void HTMLViewSourceParser::insert(const SegmentedString&)
+{
+ ASSERT_NOT_REACHED();
+}
+
+void HTMLViewSourceParser::pumpTokenizer()
+{
+ while (m_tokenizer.nextToken(m_input.current(), m_token)) {
+ m_token.end(m_input.current().numberOfCharactersConsumed());
+ document()->addSource(sourceForToken(), m_token);
+ updateTokenizerState();
+ m_token.clear(m_input.current().numberOfCharactersConsumed());
+ }
+}
+
+void HTMLViewSourceParser::append(const SegmentedString& input)
+{
+ m_input.appendToEnd(input);
+ m_source.append(input);
+ pumpTokenizer();
+}
+
+String HTMLViewSourceParser::sourceForToken()
+{
+ if (m_token.type() == HTMLToken::EndOfFile)
+ return String();
+
+ ASSERT(m_source.numberOfCharactersConsumed() == m_token.startIndex());
+ UChar* data = 0;
+ int length = m_token.endIndex() - m_token.startIndex();
+ String source = String::createUninitialized(length, data);
+ for (int i = 0; i < length; ++i) {
+ data[i] = *m_source;
+ m_source.advance();
+ }
+ return source;
+}
+
+void HTMLViewSourceParser::updateTokenizerState()
+{
+ // FIXME: The tokenizer should do this work for us.
+ if (m_token.type() != HTMLToken::StartTag)
+ return;
+
+ AtomicString tagName(m_token.name().data(), m_token.name().size());
+ m_tokenizer.setState(HTMLTreeBuilder::adjustedLexerState(m_tokenizer.state(), tagName, m_document->frame()));
+ if (tagName == HTMLNames::scriptTag) {
+ // The tree builder handles scriptTag separately from the other tokenizer
+ // state adjustments, so we need to handle it separately too.
+ ASSERT(m_tokenizer.state() == HTMLTokenizer::DataState);
+ m_tokenizer.setState(HTMLTokenizer::ScriptDataState);
+ }
+}
+
+void HTMLViewSourceParser::finish()
+{
+ if (!m_input.haveSeenEndOfFile())
+ m_input.markEndOfFile();
+ pumpTokenizer();
+ document()->finishedParsing();
+}
+
+bool HTMLViewSourceParser::finishWasCalled()
+{
+ return m_input.haveSeenEndOfFile();
+}
+
+}
diff --git a/WebCore/html/HTMLViewSourceParser.h b/WebCore/html/HTMLViewSourceParser.h
new file mode 100644
index 0000000..2571301
--- /dev/null
+++ b/WebCore/html/HTMLViewSourceParser.h
@@ -0,0 +1,77 @@
+/*
+ * 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 HTMLViewSourceParser_h
+#define HTMLViewSourceParser_h
+
+#include "DecodedDataDocumentParser.h"
+#include "HTMLInputStream.h"
+#include "HTMLToken.h"
+#include "HTMLTokenizer.h"
+#include "HTMLViewSourceDocument.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class HTMLTokenizer;
+class HTMLScriptRunner;
+class HTMLTreeBuilder;
+class HTMLPreloadScanner;
+class LegacyHTMLTreeBuilder;
+class ScriptController;
+class ScriptSourceCode;
+
+class HTMLViewSourceParser : public DecodedDataDocumentParser {
+public:
+ // FIXME: Make private with a create method.
+ HTMLViewSourceParser(HTMLViewSourceDocument* document)
+ : DecodedDataDocumentParser(document)
+ {
+ }
+
+ virtual ~HTMLViewSourceParser();
+
+private:
+ // DocumentParser
+ virtual void insert(const SegmentedString&);
+ virtual void append(const SegmentedString&);
+ virtual void finish();
+ virtual bool finishWasCalled();
+
+ HTMLViewSourceDocument* document() const { return static_cast<HTMLViewSourceDocument*>(m_document); }
+
+ void pumpTokenizer();
+ String sourceForToken();
+ void updateTokenizerState();
+
+ HTMLInputStream m_input;
+ SegmentedString m_source;
+ HTMLToken m_token;
+ HTMLTokenizer m_tokenizer;
+};
+
+}
+
+#endif
diff --git a/WebCore/html/LegacyHTMLDocumentParser.cpp b/WebCore/html/LegacyHTMLDocumentParser.cpp
deleted file mode 100644
index 980d6ed..0000000
--- a/WebCore/html/LegacyHTMLDocumentParser.cpp
+++ /dev/null
@@ -1,2126 +0,0 @@
-/*
- Copyright (C) 1997 Martin Jones (mjones@kde.org)
- (C) 1997 Torben Weis (weis@kde.org)
- (C) 1998 Waldo Bastian (bastian@kde.org)
- (C) 1999 Lars Knoll (knoll@kde.org)
- (C) 1999 Antti Koivisto (koivisto@kde.org)
- (C) 2001 Dirk Mueller (mueller@kde.org)
- Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- Copyright (C) 2005, 2006 Alexey Proskuryakov (ap@nypop.com)
- Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-#include "config.h"
-#include "LegacyHTMLDocumentParser.h"
-
-#include "Attribute.h"
-#include "CSSHelper.h"
-#include "Cache.h"
-#include "CachedScript.h"
-#include "DocLoader.h"
-#include "DocumentFragment.h"
-#include "Event.h"
-#include "EventNames.h"
-#include "Frame.h"
-#include "FrameLoader.h"
-#include "FrameView.h"
-#include "HTMLElement.h"
-#include "HTMLNames.h"
-#include "LegacyHTMLTreeBuilder.h"
-#include "HTMLScriptElement.h"
-#include "HTMLViewSourceDocument.h"
-#include "ImageLoader.h"
-#include "InspectorTimelineAgent.h"
-#include "Page.h"
-#include "LegacyPreloadScanner.h"
-#include "ScriptSourceCode.h"
-#include "ScriptValue.h"
-#include "XSSAuditor.h"
-#include <wtf/ASCIICType.h>
-#include <wtf/CurrentTime.h>
-
-#include "HTMLEntityNames.cpp"
-
-#define PRELOAD_SCANNER_ENABLED 1
-
-using namespace WTF;
-using namespace std;
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-// This value is used to define how many loops (approximately tokens)
-// the parser will make before checking if it should yield.
-// To increase responsiveness reduce both ChunkSize and TimeDelay contants.
-static const int defaultTokenizerChunkSize = 4096;
-
-// FIXME: We would like this constant to be 200ms.
-// Yielding more aggressively results in increased responsiveness and better incremental rendering.
-// It slows down overall page-load on slower machines, though, so for now we set a value of 500.
-// TimeDelay controls the maximum time the parser will run before yielding.
-// Inline script execution can cause the parser to excede this limit.
-static const double defaultTokenizerTimeDelay = 0.500;
-
-static const char commentStart [] = "<!--";
-static const char doctypeStart [] = "<!doctype";
-static const char publicStart [] = "public";
-static const char systemStart [] = "system";
-static const char scriptEnd [] = "</script";
-static const char xmpEnd [] = "</xmp";
-static const char styleEnd [] = "</style";
-static const char textareaEnd [] = "</textarea";
-static const char titleEnd [] = "</title";
-static const char iframeEnd [] = "</iframe";
-
-// Full support for MS Windows extensions to Latin-1.
-// Technically these extensions should only be activated for pages
-// marked "windows-1252" or "cp1252", but
-// in the standard Microsoft way, these extensions infect hundreds of thousands
-// of web pages. Note that people with non-latin-1 Microsoft extensions
-// are SOL.
-//
-// See: http://www.microsoft.com/globaldev/reference/WinCP.asp
-// http://www.bbsinc.com/iso8859.html
-// http://www.obviously.com/
-//
-// There may be better equivalents
-
-// We only need this for entities. For non-entity text, we handle this in the text encoding.
-
-static const UChar windowsLatin1ExtensionArray[32] = {
- 0x20AC, 0x0081, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, // 80-87
- 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008D, 0x017D, 0x008F, // 88-8F
- 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, // 90-97
- 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x009D, 0x017E, 0x0178 // 98-9F
-};
-
-static inline UChar fixUpChar(UChar c)
-{
- if ((c & ~0x1F) != 0x0080)
- return c;
- return windowsLatin1ExtensionArray[c - 0x80];
-}
-
-static inline bool tagMatch(const char* s1, const UChar* s2, unsigned length)
-{
- for (unsigned i = 0; i != length; ++i) {
- unsigned char c1 = s1[i];
- unsigned char uc1 = toASCIIUpper(static_cast<char>(c1));
- UChar c2 = s2[i];
- if (c1 != c2 && uc1 != c2)
- return false;
- }
- return true;
-}
-
-inline void Token::addAttribute(AtomicString& attrName, const AtomicString& attributeValue, bool viewSourceMode)
-{
- if (!attrName.isEmpty()) {
- ASSERT(!attrName.contains('/'));
- RefPtr<Attribute> a = Attribute::createMapped(attrName, attributeValue);
- if (!attrs) {
- attrs = NamedNodeMap::create();
- attrs->reserveInitialCapacity(10);
- }
- attrs->insertAttribute(a.release(), viewSourceMode);
- }
-
- attrName = emptyAtom;
-}
-
-// ----------------------------------------------------------------------------
-
-LegacyHTMLDocumentParser::LegacyHTMLDocumentParser(HTMLDocument* document, bool reportErrors)
- : ScriptableDocumentParser(document)
- , m_buffer(0)
- , m_scriptCode(0)
- , m_scriptCodeSize(0)
- , m_scriptCodeCapacity(0)
- , m_scriptCodeResync(0)
- , m_executingScript(0)
- , m_requestingScript(false)
- , m_hasScriptsWaitingForStylesheets(false)
- , m_timer(this, &LegacyHTMLDocumentParser::timerFired)
- , m_externalScriptsTimer(this, &LegacyHTMLDocumentParser::executeExternalScriptsTimerFired)
- , m_treeBuilder(new LegacyHTMLTreeBuilder(document, reportErrors))
- , m_inWrite(false)
- , m_fragment(false)
- , m_scriptingPermission(FragmentScriptingAllowed)
-{
- begin();
-}
-
-LegacyHTMLDocumentParser::LegacyHTMLDocumentParser(HTMLViewSourceDocument* document)
- : ScriptableDocumentParser(document, true)
- , m_buffer(0)
- , m_scriptCode(0)
- , m_scriptCodeSize(0)
- , m_scriptCodeCapacity(0)
- , m_scriptCodeResync(0)
- , m_executingScript(0)
- , m_requestingScript(false)
- , m_hasScriptsWaitingForStylesheets(false)
- , m_timer(this, &LegacyHTMLDocumentParser::timerFired)
- , m_externalScriptsTimer(this, &LegacyHTMLDocumentParser::executeExternalScriptsTimerFired)
- , m_inWrite(false)
- , m_fragment(false)
- , m_scriptingPermission(FragmentScriptingAllowed)
-{
- begin();
-}
-
-LegacyHTMLDocumentParser::LegacyHTMLDocumentParser(DocumentFragment* frag, FragmentScriptingPermission scriptingPermission)
- : ScriptableDocumentParser(frag->document())
- , m_buffer(0)
- , m_scriptCode(0)
- , m_scriptCodeSize(0)
- , m_scriptCodeCapacity(0)
- , m_scriptCodeResync(0)
- , m_executingScript(0)
- , m_requestingScript(false)
- , m_hasScriptsWaitingForStylesheets(false)
- , m_timer(this, &LegacyHTMLDocumentParser::timerFired)
- , m_externalScriptsTimer(this, &LegacyHTMLDocumentParser::executeExternalScriptsTimerFired)
- , m_treeBuilder(new LegacyHTMLTreeBuilder(frag, scriptingPermission))
- , m_inWrite(false)
- , m_fragment(true)
- , m_scriptingPermission(scriptingPermission)
-{
- begin();
-}
-
-void LegacyHTMLDocumentParser::reset()
-{
- ASSERT(m_executingScript == 0);
-
- while (!m_pendingScripts.isEmpty()) {
- CachedResourceHandle<CachedScript> cs = m_pendingScripts.takeFirst();
- ASSERT(cache()->disabled() || cs->accessCount() > 0);
- cs->removeClient(this);
- }
-
- fastFree(m_buffer);
- m_buffer = m_dest = 0;
- m_bufferSize = 0;
-
- fastFree(m_scriptCode);
- m_scriptCode = 0;
- m_scriptCodeSize = m_scriptCodeCapacity = m_scriptCodeResync = 0;
-
- m_timer.stop();
- m_externalScriptsTimer.stop();
-
- m_state.setAllowYield(false);
- m_state.setForceSynchronous(false);
-
- m_currentToken.reset();
- m_doctypeToken.reset();
- m_doctypeSearchCount = 0;
- m_doctypeSecondarySearchCount = 0;
- m_hasScriptsWaitingForStylesheets = false;
-}
-
-void LegacyHTMLDocumentParser::begin()
-{
- m_executingScript = 0;
- m_requestingScript = false;
- m_hasScriptsWaitingForStylesheets = false;
- m_state.setLoadingExtScript(false);
- reset();
- m_bufferSize = 254;
- m_buffer = static_cast<UChar*>(fastMalloc(sizeof(UChar) * 254));
- m_dest = m_buffer;
- tquote = NoQuote;
- searchCount = 0;
- m_state.setEntityState(NoEntity);
- m_scriptTagSrcAttrValue = String();
- m_pendingSrc.clear();
- m_currentPrependingSrc = 0;
- m_noMoreData = false;
- m_brokenComments = false;
- m_brokenServer = false;
- m_lineNumber = 0;
- m_currentScriptTagStartLineNumber = 0;
- m_currentTagStartLineNumber = 0;
- m_state.setForceSynchronous(false);
-
- Page* page = document()->page();
- if (page && page->hasCustomHTMLTokenizerTimeDelay())
- m_tokenizerTimeDelay = page->customHTMLTokenizerTimeDelay();
- else
- m_tokenizerTimeDelay = defaultTokenizerTimeDelay;
-
- if (page && page->hasCustomHTMLTokenizerChunkSize())
- m_tokenizerChunkSize = page->customHTMLTokenizerChunkSize();
- else
- m_tokenizerChunkSize = defaultTokenizerChunkSize;
-}
-
-void LegacyHTMLDocumentParser::setForceSynchronous(bool force)
-{
- m_state.setForceSynchronous(force);
-}
-
-LegacyHTMLDocumentParser::State LegacyHTMLDocumentParser::processListing(SegmentedString list, State state)
-{
- // This function adds the listing 'list' as
- // preformatted text-tokens to the token-collection
- while (!list.isEmpty()) {
- if (state.skipLF()) {
- state.setSkipLF(false);
- if (*list == '\n') {
- list.advance();
- continue;
- }
- }
-
- checkBuffer();
-
- if (*list == '\n' || *list == '\r') {
- if (state.discardLF())
- // Ignore this LF
- state.setDiscardLF(false); // We have discarded 1 LF
- else
- *m_dest++ = '\n';
-
- /* Check for MS-DOS CRLF sequence */
- if (*list == '\r')
- state.setSkipLF(true);
-
- list.advance();
- } else {
- state.setDiscardLF(false);
- *m_dest++ = *list;
- list.advance();
- }
- }
-
- return state;
-}
-
-LegacyHTMLDocumentParser::State LegacyHTMLDocumentParser::parseNonHTMLText(SegmentedString& src, State state)
-{
- ASSERT(state.inTextArea() || state.inTitle() || state.inIFrame() || !state.hasEntityState());
- ASSERT(!state.hasTagState());
- ASSERT(state.inXmp() + state.inTextArea() + state.inTitle() + state.inStyle() + state.inScript() + state.inIFrame() == 1);
- if (state.inScript() && !m_currentScriptTagStartLineNumber)
- m_currentScriptTagStartLineNumber = m_lineNumber;
-
- if (state.inComment())
- state = parseComment(src, state);
-
- int lastDecodedEntityPosition = -1;
- while (!src.isEmpty()) {
- checkScriptBuffer();
- UChar ch = *src;
-
- if (!m_scriptCodeResync && !m_brokenComments &&
- !state.inXmp() && ch == '-' && m_scriptCodeSize >= 3 && !src.escaped() &&
- m_scriptCode[m_scriptCodeSize - 3] == '<' && m_scriptCode[m_scriptCodeSize - 2] == '!' && m_scriptCode[m_scriptCodeSize - 1] == '-' &&
- (lastDecodedEntityPosition < m_scriptCodeSize - 3)) {
- state.setInComment(true);
- state = parseComment(src, state);
- continue;
- }
- if (m_scriptCodeResync && !tquote && ch == '>') {
- src.advancePastNonNewline();
- m_scriptCodeSize = m_scriptCodeResync - 1;
- m_scriptCodeResync = 0;
- m_scriptCode[m_scriptCodeSize] = m_scriptCode[m_scriptCodeSize + 1] = 0;
- if (state.inScript())
- state = scriptHandler(state);
- else {
- state = processListing(SegmentedString(String(m_scriptCode, m_scriptCodeSize)), state);
- processToken();
- if (state.inStyle()) {
- m_currentToken.tagName = styleTag.localName();
- m_currentToken.beginTag = false;
- } else if (state.inTextArea()) {
- m_currentToken.tagName = textareaTag.localName();
- m_currentToken.beginTag = false;
- } else if (state.inTitle()) {
- m_currentToken.tagName = titleTag.localName();
- m_currentToken.beginTag = false;
- } else if (state.inXmp()) {
- m_currentToken.tagName = xmpTag.localName();
- m_currentToken.beginTag = false;
- } else if (state.inIFrame()) {
- m_currentToken.tagName = iframeTag.localName();
- m_currentToken.beginTag = false;
- }
- processToken();
- state.setInStyle(false);
- state.setInScript(false);
- state.setInTextArea(false);
- state.setInTitle(false);
- state.setInXmp(false);
- state.setInIFrame(false);
- tquote = NoQuote;
- m_scriptCodeSize = m_scriptCodeResync = 0;
- }
- return state;
- }
- // possible end of tagname, lets check.
- if (!m_scriptCodeResync && !state.escaped() && !src.escaped() && (ch == '>' || ch == '/' || isASCIISpace(ch)) &&
- m_scriptCodeSize >= m_searchStopperLength &&
- tagMatch(m_searchStopper, m_scriptCode + m_scriptCodeSize - m_searchStopperLength, m_searchStopperLength) &&
- (lastDecodedEntityPosition < m_scriptCodeSize - m_searchStopperLength)) {
- m_scriptCodeResync = m_scriptCodeSize-m_searchStopperLength+1;
- tquote = NoQuote;
- continue;
- }
- if (m_scriptCodeResync && !state.escaped()) {
- if (ch == '\"')
- tquote = (tquote == NoQuote) ? DoubleQuote : ((tquote == SingleQuote) ? SingleQuote : NoQuote);
- else if (ch == '\'')
- tquote = (tquote == NoQuote) ? SingleQuote : (tquote == DoubleQuote) ? DoubleQuote : NoQuote;
- else if (tquote != NoQuote && (ch == '\r' || ch == '\n'))
- tquote = NoQuote;
- }
- state.setEscaped(!state.escaped() && ch == '\\');
- if (!m_scriptCodeResync && (state.inTextArea() || state.inTitle() || state.inIFrame()) && !src.escaped() && ch == '&') {
- UChar* scriptCodeDest = m_scriptCode + m_scriptCodeSize;
- src.advancePastNonNewline();
- state = parseEntity(src, scriptCodeDest, state, m_cBufferPos, true, false);
- if (scriptCodeDest == m_scriptCode + m_scriptCodeSize)
- lastDecodedEntityPosition = m_scriptCodeSize;
- else
- m_scriptCodeSize = scriptCodeDest - m_scriptCode;
- } else {
- m_scriptCode[m_scriptCodeSize++] = ch;
- src.advance(m_lineNumber);
- }
- }
-
- return state;
-}
-
-LegacyHTMLDocumentParser::State LegacyHTMLDocumentParser::scriptHandler(State state)
-{
- // We are inside a <script>
- bool doScriptExec = false;
- int startLine = m_currentScriptTagStartLineNumber + 1; // Script line numbers are 1 based, HTMLTokenzier line numbers are 0 based
-
- // Reset m_currentScriptTagStartLineNumber to indicate that we've finished parsing the current script element
- m_currentScriptTagStartLineNumber = 0;
-
- // (Bugzilla 3837) Scripts following a frameset element should not execute or,
- // in the case of extern scripts, even load.
- bool followingFrameset = (document()->body() && document()->body()->hasTagName(framesetTag));
-
- CachedScript* cs = 0;
- // don't load external scripts for standalone documents (for now)
- if (!inViewSourceMode()) {
- if (!m_scriptTagSrcAttrValue.isEmpty() && document()->frame()) {
- // forget what we just got; load from src url instead
- if (!m_treeBuilder->skipMode() && !followingFrameset) {
- // The parser might have been stopped by for example a window.close call in an earlier script.
- // If so, we don't want to load scripts.
- if (!m_parserStopped && m_scriptNode->dispatchBeforeLoadEvent(m_scriptTagSrcAttrValue) &&
- (cs = document()->docLoader()->requestScript(m_scriptTagSrcAttrValue, m_scriptTagCharsetAttrValue)))
- m_pendingScripts.append(cs);
- else
- m_scriptNode = 0;
- } else
- m_scriptNode = 0;
- m_scriptTagSrcAttrValue = String();
- } else {
- // Parse m_scriptCode containing <script> info
- doScriptExec = m_scriptNode->shouldExecuteAsJavaScript();
-#if ENABLE(XHTMLMP)
- if (!doScriptExec)
- document()->setShouldProcessNoscriptElement(true);
-#endif
- m_scriptNode = 0;
- }
- }
-
- state = processListing(SegmentedString(String(m_scriptCode, m_scriptCodeSize)), state);
- RefPtr<Node> node = processToken();
-
- if (node && m_scriptingPermission == FragmentScriptingNotAllowed) {
- ExceptionCode ec;
- node->remove(ec);
- node = 0;
- }
-
- String scriptString = node ? node->textContent() : "";
- m_currentToken.tagName = scriptTag.localName();
- m_currentToken.beginTag = false;
- processToken();
-
- state.setInScript(false);
- m_scriptCodeSize = m_scriptCodeResync = 0;
-
- // FIXME: The script should be syntax highlighted.
- if (inViewSourceMode())
- return state;
-
- SegmentedString* savedPrependingSrc = m_currentPrependingSrc;
- SegmentedString prependingSrc;
- m_currentPrependingSrc = &prependingSrc;
-
- if (!m_treeBuilder->skipMode() && !followingFrameset) {
- if (cs) {
- if (savedPrependingSrc)
- savedPrependingSrc->append(m_src);
- else
- m_pendingSrc.prepend(m_src);
- setSrc(SegmentedString());
-
- // the ref() call below may call notifyFinished if the script is already in cache,
- // and that mucks with the state directly, so we must write it back to the object.
- m_state = state;
- bool savedRequestingScript = m_requestingScript;
- m_requestingScript = true;
- cs->addClient(this);
- m_requestingScript = savedRequestingScript;
- state = m_state;
- // will be 0 if script was already loaded and ref() executed it
- if (!m_pendingScripts.isEmpty())
- state.setLoadingExtScript(true);
- } else if (!m_fragment && doScriptExec) {
- if (!m_executingScript)
- m_pendingSrc.prepend(m_src);
- else
- prependingSrc = m_src;
- setSrc(SegmentedString());
- state = scriptExecution(ScriptSourceCode(scriptString, document()->frame() ? document()->frame()->document()->url() : KURL(), startLine), state);
- }
- }
-
- if (!m_executingScript && !state.loadingExtScript()) {
- m_src.append(m_pendingSrc);
- m_pendingSrc.clear();
- } else if (!prependingSrc.isEmpty()) {
- // restore first so that the write appends in the right place
- // (does not hurt to do it again below)
- m_currentPrependingSrc = savedPrependingSrc;
-
- // we need to do this slightly modified bit of one of the write() cases
- // because we want to prepend to m_pendingSrc rather than appending
- // if there's no previous prependingSrc
- if (!m_pendingScripts.isEmpty()) {
- if (m_currentPrependingSrc)
- m_currentPrependingSrc->append(prependingSrc);
- else
- m_pendingSrc.prepend(prependingSrc);
- } else {
- m_state = state;
- write(prependingSrc, false);
- state = m_state;
- }
- }
-
-#if PRELOAD_SCANNER_ENABLED
- if (!m_pendingScripts.isEmpty() && !m_executingScript) {
- if (!m_preloadScanner)
- m_preloadScanner.set(new LegacyPreloadScanner(document()));
- if (!m_preloadScanner->inProgress()) {
- m_preloadScanner->begin();
- m_preloadScanner->write(m_pendingSrc);
- }
- }
-#endif
- m_currentPrependingSrc = savedPrependingSrc;
-
- return state;
-}
-
-LegacyHTMLDocumentParser::State LegacyHTMLDocumentParser::scriptExecution(const ScriptSourceCode& sourceCode, State state)
-{
- if (m_fragment || !document()->frame())
- return state;
- m_executingScript++;
-
- SegmentedString* savedPrependingSrc = m_currentPrependingSrc;
- SegmentedString prependingSrc;
- m_currentPrependingSrc = &prependingSrc;
-
- m_state = state;
- document()->frame()->script()->executeScript(sourceCode);
- state = m_state;
-
- state.setAllowYield(true);
-
- m_executingScript--;
-
- if (!m_executingScript && !state.loadingExtScript()) {
- m_pendingSrc.prepend(prependingSrc);
- m_src.append(m_pendingSrc);
- m_pendingSrc.clear();
- } else if (!prependingSrc.isEmpty()) {
- // restore first so that the write appends in the right place
- // (does not hurt to do it again below)
- m_currentPrependingSrc = savedPrependingSrc;
-
- // we need to do this slightly modified bit of one of the write() cases
- // because we want to prepend to m_pendingSrc rather than appending
- // if there's no previous prependingSrc
- if (!m_pendingScripts.isEmpty()) {
- if (m_currentPrependingSrc)
- m_currentPrependingSrc->append(prependingSrc);
- else
- m_pendingSrc.prepend(prependingSrc);
-
-#if PRELOAD_SCANNER_ENABLED
- // We are stuck waiting for another script. Lets check the source that
- // was just document.write()n for anything to load.
- LegacyPreloadScanner documentWritePreloadScanner(document());
- documentWritePreloadScanner.begin();
- documentWritePreloadScanner.write(prependingSrc);
- documentWritePreloadScanner.end();
-#endif
- } else {
- m_state = state;
- write(prependingSrc, false);
- state = m_state;
- }
- }
-
- m_currentPrependingSrc = savedPrependingSrc;
-
- return state;
-}
-
-LegacyHTMLDocumentParser::State LegacyHTMLDocumentParser::parseComment(SegmentedString& src, State state)
-{
- // FIXME: Why does this code even run for comments inside <script> and <style>? This seems bogus.
- checkScriptBuffer(src.length());
- while (!src.isEmpty()) {
- UChar ch = *src;
- m_scriptCode[m_scriptCodeSize++] = ch;
- if (ch == '>') {
- bool handleBrokenComments = m_brokenComments && !(state.inScript() || state.inStyle());
- int endCharsCount = 1; // start off with one for the '>' character
- if (m_scriptCodeSize > 2 && m_scriptCode[m_scriptCodeSize-3] == '-' && m_scriptCode[m_scriptCodeSize-2] == '-') {
- endCharsCount = 3;
- } else if (m_scriptCodeSize > 3 && m_scriptCode[m_scriptCodeSize-4] == '-' && m_scriptCode[m_scriptCodeSize-3] == '-' &&
- m_scriptCode[m_scriptCodeSize-2] == '!') {
- // Other browsers will accept --!> as a close comment, even though it's
- // not technically valid.
- endCharsCount = 4;
- }
- if (handleBrokenComments || endCharsCount > 1) {
- src.advancePastNonNewline();
- if (!(state.inTitle() || state.inScript() || state.inXmp() || state.inTextArea() || state.inStyle() || state.inIFrame())) {
- checkScriptBuffer();
- m_scriptCode[m_scriptCodeSize] = 0;
- m_scriptCode[m_scriptCodeSize + 1] = 0;
- m_currentToken.tagName = commentAtom;
- m_currentToken.beginTag = true;
- state = processListing(SegmentedString(String(m_scriptCode, m_scriptCodeSize - endCharsCount)), state);
- processToken();
- m_currentToken.tagName = commentAtom;
- m_currentToken.beginTag = false;
- processToken();
- m_scriptCodeSize = 0;
- }
- state.setInComment(false);
- return state; // Finished parsing comment
- }
- }
- src.advance(m_lineNumber);
- }
-
- return state;
-}
-
-LegacyHTMLDocumentParser::State LegacyHTMLDocumentParser::parseServer(SegmentedString& src, State state)
-{
- checkScriptBuffer(src.length());
- while (!src.isEmpty()) {
- UChar ch = *src;
- m_scriptCode[m_scriptCodeSize++] = ch;
- if (ch == '>' && m_scriptCodeSize > 1 && m_scriptCode[m_scriptCodeSize - 2] == '%') {
- src.advancePastNonNewline();
- state.setInServer(false);
- m_scriptCodeSize = 0;
- return state; // Finished parsing server include
- }
- src.advance(m_lineNumber);
- }
- return state;
-}
-
-LegacyHTMLDocumentParser::State LegacyHTMLDocumentParser::parseProcessingInstruction(SegmentedString& src, State state)
-{
- UChar oldchar = 0;
- while (!src.isEmpty()) {
- UChar chbegin = *src;
- if (chbegin == '\'')
- tquote = tquote == SingleQuote ? NoQuote : SingleQuote;
- else if (chbegin == '\"')
- tquote = tquote == DoubleQuote ? NoQuote : DoubleQuote;
- // Look for '?>'
- // Some crappy sites omit the "?" before it, so
- // we look for an unquoted '>' instead. (IE compatible)
- else if (chbegin == '>' && (!tquote || oldchar == '?')) {
- // We got a '?>' sequence
- state.setInProcessingInstruction(false);
- src.advancePastNonNewline();
- state.setDiscardLF(true);
- return state; // Finished parsing comment!
- }
- src.advance(m_lineNumber);
- oldchar = chbegin;
- }
-
- return state;
-}
-
-LegacyHTMLDocumentParser::State LegacyHTMLDocumentParser::parseText(SegmentedString& src, State state)
-{
- while (!src.isEmpty()) {
- UChar cc = *src;
-
- if (state.skipLF()) {
- state.setSkipLF(false);
- if (cc == '\n') {
- src.advancePastNewline(m_lineNumber);
- continue;
- }
- }
-
- // do we need to enlarge the buffer?
- checkBuffer();
-
- if (cc == '\r') {
- state.setSkipLF(true);
- *m_dest++ = '\n';
- } else
- *m_dest++ = cc;
- src.advance(m_lineNumber);
- }
-
- return state;
-}
-
-
-LegacyHTMLDocumentParser::State LegacyHTMLDocumentParser::parseEntity(SegmentedString& src, UChar*& dest, State state, unsigned& cBufferPos, bool start, bool parsingTag)
-{
- if (start) {
- cBufferPos = 0;
- state.setEntityState(SearchEntity);
- EntityUnicodeValue = 0;
- }
-
- while (!src.isEmpty()) {
- UChar cc = *src;
- switch (state.entityState()) {
- case NoEntity:
- ASSERT(state.entityState() != NoEntity);
- return state;
-
- case SearchEntity:
- if (cc == '#') {
- m_cBuffer[cBufferPos++] = cc;
- src.advancePastNonNewline();
- state.setEntityState(NumericSearch);
- } else
- state.setEntityState(EntityName);
- break;
-
- case NumericSearch:
- if (cc == 'x' || cc == 'X') {
- m_cBuffer[cBufferPos++] = cc;
- src.advancePastNonNewline();
- state.setEntityState(Hexadecimal);
- } else if (cc >= '0' && cc <= '9')
- state.setEntityState(Decimal);
- else
- state.setEntityState(SearchSemicolon);
- break;
-
- case Hexadecimal: {
- int ll = min(src.length(), 10 - cBufferPos);
- while (ll--) {
- cc = *src;
- if (!((cc >= '0' && cc <= '9') || (cc >= 'a' && cc <= 'f') || (cc >= 'A' && cc <= 'F'))) {
- state.setEntityState(SearchSemicolon);
- break;
- }
- int digit;
- if (cc < 'A')
- digit = cc - '0';
- else
- digit = (cc - 'A' + 10) & 0xF; // handle both upper and lower case without a branch
- EntityUnicodeValue = EntityUnicodeValue * 16 + digit;
- m_cBuffer[cBufferPos++] = cc;
- src.advancePastNonNewline();
- }
- if (cBufferPos == 10)
- state.setEntityState(SearchSemicolon);
- break;
- }
- case Decimal:
- {
- int ll = min(src.length(), 9-cBufferPos);
- while (ll--) {
- cc = *src;
-
- if (!(cc >= '0' && cc <= '9')) {
- state.setEntityState(SearchSemicolon);
- break;
- }
-
- EntityUnicodeValue = EntityUnicodeValue * 10 + (cc - '0');
- m_cBuffer[cBufferPos++] = cc;
- src.advancePastNonNewline();
- }
- if (cBufferPos == 9)
- state.setEntityState(SearchSemicolon);
- break;
- }
- case EntityName:
- {
- int ll = min(src.length(), 9-cBufferPos);
- while (ll--) {
- cc = *src;
-
- if (!((cc >= 'a' && cc <= 'z') || (cc >= '0' && cc <= '9') || (cc >= 'A' && cc <= 'Z'))) {
- state.setEntityState(SearchSemicolon);
- break;
- }
-
- m_cBuffer[cBufferPos++] = cc;
- src.advancePastNonNewline();
- }
- if (cBufferPos == 9)
- state.setEntityState(SearchSemicolon);
- if (state.entityState() == SearchSemicolon) {
- if (cBufferPos > 1) {
- // Since the maximum length of entity name is 9,
- // so a single char array which is allocated on
- // the stack, its length is 10, should be OK.
- // Also if we have an illegal character, we treat it
- // as illegal entity name.
- unsigned testedEntityNameLen = 0;
- char tmpEntityNameBuffer[10];
-
- ASSERT(cBufferPos < 10);
- for (; testedEntityNameLen < cBufferPos; ++testedEntityNameLen) {
- if (m_cBuffer[testedEntityNameLen] > 0x7e)
- break;
- tmpEntityNameBuffer[testedEntityNameLen] = m_cBuffer[testedEntityNameLen];
- }
-
- const Entity *e;
-
- if (testedEntityNameLen == cBufferPos)
- e = findEntity(tmpEntityNameBuffer, cBufferPos);
- else
- e = 0;
-
- if (e)
- EntityUnicodeValue = e->code;
-
- // be IE compatible
- if (parsingTag && EntityUnicodeValue > 255 && *src != ';')
- EntityUnicodeValue = 0;
- }
- }
- else
- break;
- }
- case SearchSemicolon:
- // Don't allow values that are more than 21 bits.
- if (EntityUnicodeValue > 0 && EntityUnicodeValue <= 0x10FFFF) {
- if (!inViewSourceMode()) {
- if (*src == ';')
- src.advancePastNonNewline();
- if (EntityUnicodeValue <= 0xFFFF) {
- checkBuffer();
- src.push(fixUpChar(EntityUnicodeValue));
- } else {
- // Convert to UTF-16, using surrogate code points.
- checkBuffer(2);
- src.push(U16_LEAD(EntityUnicodeValue));
- src.push(U16_TRAIL(EntityUnicodeValue));
- }
- } else {
- // FIXME: We should eventually colorize entities by sending them as a special token.
- // 12 bytes required: up to 10 bytes in m_cBuffer plus the
- // leading '&' and trailing ';'
- checkBuffer(12);
- *dest++ = '&';
- for (unsigned i = 0; i < cBufferPos; i++)
- dest[i] = m_cBuffer[i];
- dest += cBufferPos;
- if (*src == ';') {
- *dest++ = ';';
- src.advancePastNonNewline();
- }
- }
- } else {
- // 11 bytes required: up to 10 bytes in m_cBuffer plus the
- // leading '&'
- checkBuffer(11);
- // ignore the sequence, add it to the buffer as plaintext
- *dest++ = '&';
- for (unsigned i = 0; i < cBufferPos; i++)
- dest[i] = m_cBuffer[i];
- dest += cBufferPos;
- }
-
- state.setEntityState(NoEntity);
- return state;
- }
- }
-
- return state;
-}
-
-LegacyHTMLDocumentParser::State LegacyHTMLDocumentParser::parseDoctype(SegmentedString& src, State state)
-{
- ASSERT(state.inDoctype());
- while (!src.isEmpty() && state.inDoctype()) {
- UChar c = *src;
- bool isWhitespace = c == '\r' || c == '\n' || c == '\t' || c == ' ';
- switch (m_doctypeToken.state()) {
- case DoctypeBegin: {
- m_doctypeToken.setState(DoctypeBeforeName);
- if (isWhitespace) {
- src.advance(m_lineNumber);
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- }
- break;
- }
- case DoctypeBeforeName: {
- if (c == '>') {
- // Malformed. Just exit.
- src.advancePastNonNewline();
- state.setInDoctype(false);
- if (inViewSourceMode())
- processDoctypeToken();
- } else if (isWhitespace) {
- src.advance(m_lineNumber);
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- } else
- m_doctypeToken.setState(DoctypeName);
- break;
- }
- case DoctypeName: {
- if (c == '>') {
- // Valid doctype. Emit it.
- src.advancePastNonNewline();
- state.setInDoctype(false);
- processDoctypeToken();
- } else if (isWhitespace) {
- m_doctypeSearchCount = 0; // Used now to scan for PUBLIC
- m_doctypeSecondarySearchCount = 0; // Used now to scan for SYSTEM
- m_doctypeToken.setState(DoctypeAfterName);
- src.advance(m_lineNumber);
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- } else {
- src.advancePastNonNewline();
- m_doctypeToken.m_name.append(c);
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- }
- break;
- }
- case DoctypeAfterName: {
- if (c == '>') {
- // Valid doctype. Emit it.
- src.advancePastNonNewline();
- state.setInDoctype(false);
- processDoctypeToken();
- } else if (!isWhitespace) {
- src.advancePastNonNewline();
- if (toASCIILower(c) == publicStart[m_doctypeSearchCount]) {
- m_doctypeSearchCount++;
- if (m_doctypeSearchCount == 6)
- // Found 'PUBLIC' sequence
- m_doctypeToken.setState(DoctypeBeforePublicID);
- } else if (m_doctypeSearchCount > 0) {
- m_doctypeSearchCount = 0;
- m_doctypeToken.setState(DoctypeBogus);
- } else if (toASCIILower(c) == systemStart[m_doctypeSecondarySearchCount]) {
- m_doctypeSecondarySearchCount++;
- if (m_doctypeSecondarySearchCount == 6)
- // Found 'SYSTEM' sequence
- m_doctypeToken.setState(DoctypeBeforeSystemID);
- } else {
- m_doctypeSecondarySearchCount = 0;
- m_doctypeToken.setState(DoctypeBogus);
- }
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- } else {
- src.advance(m_lineNumber); // Whitespace keeps us in the after name state.
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- }
- break;
- }
- case DoctypeBeforePublicID: {
- if (c == '\"' || c == '\'') {
- tquote = c == '\"' ? DoubleQuote : SingleQuote;
- m_doctypeToken.setState(DoctypePublicID);
- src.advancePastNonNewline();
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- } else if (c == '>') {
- // Considered bogus. Don't process the doctype.
- src.advancePastNonNewline();
- state.setInDoctype(false);
- if (inViewSourceMode())
- processDoctypeToken();
- } else if (isWhitespace) {
- src.advance(m_lineNumber);
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- } else
- m_doctypeToken.setState(DoctypeBogus);
- break;
- }
- case DoctypePublicID: {
- if ((c == '\"' && tquote == DoubleQuote) || (c == '\'' && tquote == SingleQuote)) {
- src.advancePastNonNewline();
- m_doctypeToken.setState(DoctypeAfterPublicID);
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- } else if (c == '>') {
- // Considered bogus. Don't process the doctype.
- src.advancePastNonNewline();
- state.setInDoctype(false);
- if (inViewSourceMode())
- processDoctypeToken();
- } else {
- m_doctypeToken.m_publicID.append(c);
- src.advance(m_lineNumber);
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- }
- break;
- }
- case DoctypeAfterPublicID:
- if (c == '\"' || c == '\'') {
- tquote = c == '\"' ? DoubleQuote : SingleQuote;
- m_doctypeToken.setState(DoctypeSystemID);
- src.advancePastNonNewline();
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- } else if (c == '>') {
- // Valid doctype. Emit it now.
- src.advancePastNonNewline();
- state.setInDoctype(false);
- processDoctypeToken();
- } else if (isWhitespace) {
- src.advance(m_lineNumber);
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- } else
- m_doctypeToken.setState(DoctypeBogus);
- break;
- case DoctypeBeforeSystemID:
- if (c == '\"' || c == '\'') {
- tquote = c == '\"' ? DoubleQuote : SingleQuote;
- m_doctypeToken.setState(DoctypeSystemID);
- src.advancePastNonNewline();
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- } else if (c == '>') {
- // Considered bogus. Don't process the doctype.
- src.advancePastNonNewline();
- state.setInDoctype(false);
- } else if (isWhitespace) {
- src.advance(m_lineNumber);
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- } else
- m_doctypeToken.setState(DoctypeBogus);
- break;
- case DoctypeSystemID:
- if ((c == '\"' && tquote == DoubleQuote) || (c == '\'' && tquote == SingleQuote)) {
- src.advancePastNonNewline();
- m_doctypeToken.setState(DoctypeAfterSystemID);
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- } else if (c == '>') {
- // Considered bogus. Don't process the doctype.
- src.advancePastNonNewline();
- state.setInDoctype(false);
- if (inViewSourceMode())
- processDoctypeToken();
- } else {
- m_doctypeToken.m_systemID.append(c);
- src.advance(m_lineNumber);
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- }
- break;
- case DoctypeAfterSystemID:
- if (c == '>') {
- // Valid doctype. Emit it now.
- src.advancePastNonNewline();
- state.setInDoctype(false);
- processDoctypeToken();
- } else if (isWhitespace) {
- src.advance(m_lineNumber);
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- } else
- m_doctypeToken.setState(DoctypeBogus);
- break;
- case DoctypeBogus:
- if (c == '>') {
- // Done with the bogus doctype.
- src.advancePastNonNewline();
- state.setInDoctype(false);
- if (inViewSourceMode())
- processDoctypeToken();
- } else {
- src.advance(m_lineNumber); // Just keep scanning for '>'
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(c);
- }
- break;
- default:
- break;
- }
- }
- return state;
-}
-
-LegacyHTMLDocumentParser::State LegacyHTMLDocumentParser::parseTag(SegmentedString& src, State state)
-{
- ASSERT(!state.hasEntityState());
-
- unsigned cBufferPos = m_cBufferPos;
-
- bool lastIsSlash = false;
-
- while (!src.isEmpty()) {
- checkBuffer();
- switch (state.tagState()) {
- case NoTag:
- {
- m_cBufferPos = cBufferPos;
- return state;
- }
- case TagName:
- {
- if (searchCount > 0) {
- if (*src == commentStart[searchCount]) {
- searchCount++;
- if (searchCount == 2)
- m_doctypeSearchCount++; // A '!' is also part of a doctype, so we are moving through that still as well.
- else
- m_doctypeSearchCount = 0;
- if (searchCount == 4) {
- // Found '<!--' sequence
- src.advancePastNonNewline();
- m_dest = m_buffer; // ignore the previous part of this tag
- state.setInComment(true);
- state.setTagState(NoTag);
-
- // Fix bug 34302 at kde.bugs.org. Go ahead and treat
- // <!--> as a valid comment, since both mozilla and IE on windows
- // can handle this case. Only do this in quirks mode. -dwh
- if (!src.isEmpty() && *src == '>' && document()->inCompatMode()) {
- state.setInComment(false);
- src.advancePastNonNewline();
- if (!src.isEmpty())
- m_cBuffer[cBufferPos++] = *src;
- } else
- state = parseComment(src, state);
-
- m_cBufferPos = cBufferPos;
- return state; // Finished parsing tag!
- }
- m_cBuffer[cBufferPos++] = *src;
- src.advancePastNonNewline();
- break;
- } else
- searchCount = 0; // Stop looking for '<!--' sequence
- }
-
- if (m_doctypeSearchCount > 0) {
- if (toASCIILower(*src) == doctypeStart[m_doctypeSearchCount]) {
- m_doctypeSearchCount++;
- m_cBuffer[cBufferPos++] = *src;
- src.advancePastNonNewline();
- if (m_doctypeSearchCount == 9) {
- // Found '<!DOCTYPE' sequence
- state.setInDoctype(true);
- state.setTagState(NoTag);
- m_doctypeToken.reset();
- if (inViewSourceMode())
- m_doctypeToken.m_source.append(m_cBuffer, cBufferPos);
- state = parseDoctype(src, state);
- m_cBufferPos = cBufferPos;
- return state;
- }
- break;
- } else
- m_doctypeSearchCount = 0; // Stop looking for '<!DOCTYPE' sequence
- }
-
- bool finish = false;
- unsigned int ll = min(src.length(), CBUFLEN - cBufferPos);
- while (ll--) {
- UChar curchar = *src;
- if (isASCIISpace(curchar) || curchar == '>' || curchar == '<') {
- finish = true;
- break;
- }
-
- // tolower() shows up on profiles. This is faster!
- if (curchar >= 'A' && curchar <= 'Z' && !inViewSourceMode())
- m_cBuffer[cBufferPos++] = curchar + ('a' - 'A');
- else
- m_cBuffer[cBufferPos++] = curchar;
- src.advancePastNonNewline();
- }
-
- // Disadvantage: we add the possible rest of the tag
- // as attribute names. ### judge if this causes problems
- if (finish || CBUFLEN == cBufferPos) {
- bool beginTag;
- UChar* ptr = m_cBuffer;
- unsigned int len = cBufferPos;
- m_cBuffer[cBufferPos] = '\0';
- if ((cBufferPos > 0) && (*ptr == '/')) {
- // End Tag
- beginTag = false;
- ptr++;
- len--;
- }
- else
- // Start Tag
- beginTag = true;
-
- // Ignore the / in fake xml tags like <br/>. We trim off the "/" so that we'll get "br" as the tag name and not "br/".
- if (len > 1 && ptr[len-1] == '/' && !inViewSourceMode())
- ptr[--len] = '\0';
-
- // Now that we've shaved off any invalid / that might have followed the name), make the tag.
- // FIXME: FireFox and WinIE turn !foo nodes into comments, we ignore comments. (fast/parser/tag-with-exclamation-point.html)
- if (ptr[0] != '!' || inViewSourceMode()) {
- m_currentToken.tagName = AtomicString(ptr);
- m_currentToken.beginTag = beginTag;
- }
- m_dest = m_buffer;
- state.setTagState(SearchAttribute);
- cBufferPos = 0;
- }
- break;
- }
- case SearchAttribute:
- while (!src.isEmpty()) {
- UChar curchar = *src;
- // In this mode just ignore any quotes we encounter and treat them like spaces.
- if (!isASCIISpace(curchar) && curchar != '\'' && curchar != '"') {
- if (curchar == '<' || curchar == '>')
- state.setTagState(SearchEnd);
- else
- state.setTagState(AttributeName);
-
- cBufferPos = 0;
- break;
- }
- if (inViewSourceMode())
- m_currentToken.addViewSourceChar(curchar);
- src.advance(m_lineNumber);
- }
- break;
- case AttributeName:
- {
- m_rawAttributeBeforeValue.clear();
- int ll = min(src.length(), CBUFLEN - cBufferPos);
- while (ll--) {
- UChar curchar = *src;
- // If we encounter a "/" when scanning an attribute name, treat it as a delimiter. This allows the
- // cases like <input type=checkbox checked/> to work (and accommodates XML-style syntax as per HTML5).
- if (curchar <= '>' && (curchar >= '<' || isASCIISpace(curchar) || curchar == '/')) {
- m_cBuffer[cBufferPos] = '\0';
- m_attrName = AtomicString(m_cBuffer);
- m_dest = m_buffer;
- *m_dest++ = 0;
- state.setTagState(SearchEqual);
- if (inViewSourceMode())
- m_currentToken.addViewSourceChar('a');
- break;
- }
-
- // tolower() shows up on profiles. This is faster!
- if (curchar >= 'A' && curchar <= 'Z' && !inViewSourceMode())
- m_cBuffer[cBufferPos++] = curchar + ('a' - 'A');
- else
- m_cBuffer[cBufferPos++] = curchar;
-
- m_rawAttributeBeforeValue.append(curchar);
- src.advance(m_lineNumber);
- }
- if (cBufferPos == CBUFLEN) {
- m_cBuffer[cBufferPos] = '\0';
- m_attrName = AtomicString(m_cBuffer);
- m_dest = m_buffer;
- *m_dest++ = 0;
- state.setTagState(SearchEqual);
- if (inViewSourceMode())
- m_currentToken.addViewSourceChar('a');
- }
- break;
- }
- case SearchEqual:
- while (!src.isEmpty()) {
- UChar curchar = *src;
-
- if (lastIsSlash && curchar == '>') {
- // This is a quirk (with a long sad history). We have to do this
- // since widgets do <script src="foo.js"/> and expect the tag to close.
- if (m_currentToken.tagName == scriptTag)
- m_currentToken.selfClosingTag = true;
- m_currentToken.brokenXMLStyle = true;
- }
-
- // In this mode just ignore any quotes or slashes we encounter and treat them like spaces.
- if (!isASCIISpace(curchar) && curchar != '\'' && curchar != '"' && curchar != '/') {
- if (curchar == '=') {
- state.setTagState(SearchValue);
- if (inViewSourceMode())
- m_currentToken.addViewSourceChar(curchar);
- m_rawAttributeBeforeValue.append(curchar);
- src.advancePastNonNewline();
- } else {
- m_currentToken.addAttribute(m_attrName, emptyAtom, inViewSourceMode());
- m_dest = m_buffer;
- state.setTagState(SearchAttribute);
- lastIsSlash = false;
- }
- break;
- }
-
- lastIsSlash = curchar == '/';
-
- if (inViewSourceMode())
- m_currentToken.addViewSourceChar(curchar);
- m_rawAttributeBeforeValue.append(curchar);
- src.advance(m_lineNumber);
- }
- break;
- case SearchValue:
- while (!src.isEmpty()) {
- UChar curchar = *src;
- if (!isASCIISpace(curchar)) {
- if (curchar == '\'' || curchar == '\"') {
- tquote = curchar == '\"' ? DoubleQuote : SingleQuote;
- state.setTagState(QuotedValue);
- if (inViewSourceMode())
- m_currentToken.addViewSourceChar(curchar);
- m_rawAttributeBeforeValue.append(curchar);
- src.advancePastNonNewline();
- } else
- state.setTagState(Value);
-
- break;
- }
- if (inViewSourceMode())
- m_currentToken.addViewSourceChar(curchar);
- m_rawAttributeBeforeValue.append(curchar);
- src.advance(m_lineNumber);
- }
- break;
- case QuotedValue:
- while (!src.isEmpty()) {
- checkBuffer();
-
- UChar curchar = *src;
- if (curchar <= '>' && !src.escaped()) {
- if (curchar == '>' && m_attrName.isEmpty()) {
- // Handle a case like <img '>. Just go ahead and be willing
- // to close the whole tag. Don't consume the character and
- // just go back into SearchEnd while ignoring the whole
- // value.
- // FIXME: Note that this is actually not a very good solution.
- // It doesn't handle the general case of
- // unmatched quotes among attributes that have names. -dwh
- while (m_dest > m_buffer + 1 && (m_dest[-1] == '\n' || m_dest[-1] == '\r'))
- m_dest--; // remove trailing newlines
- AtomicString attributeValue(m_buffer + 1, m_dest - m_buffer - 1);
- if (!attributeValue.contains('/'))
- m_attrName = attributeValue; // Just make the name/value match. (FIXME: Is this some WinIE quirk?)
- m_currentToken.addAttribute(m_attrName, attributeValue, inViewSourceMode());
- if (inViewSourceMode())
- m_currentToken.addViewSourceChar('x');
- state.setTagState(SearchAttribute);
- m_dest = m_buffer;
- tquote = NoQuote;
- break;
- }
-
- if (curchar == '&') {
- src.advancePastNonNewline();
- state = parseEntity(src, m_dest, state, cBufferPos, true, true);
- break;
- }
-
- if ((tquote == SingleQuote && curchar == '\'') || (tquote == DoubleQuote && curchar == '\"')) {
- // some <input type=hidden> rely on trailing spaces. argh
- while (m_dest > m_buffer + 1 && (m_dest[-1] == '\n' || m_dest[-1] == '\r'))
- m_dest--; // remove trailing newlines
- AtomicString attributeValue(m_buffer + 1, m_dest - m_buffer - 1);
- if (m_attrName.isEmpty() && !attributeValue.contains('/')) {
- m_attrName = attributeValue; // Make the name match the value. (FIXME: Is this a WinIE quirk?)
- if (inViewSourceMode())
- m_currentToken.addViewSourceChar('x');
- } else if (inViewSourceMode())
- m_currentToken.addViewSourceChar('v');
-
- if (m_currentToken.beginTag && m_currentToken.tagName == scriptTag && !inViewSourceMode() && !m_treeBuilder->skipMode() && m_attrName == srcAttr) {
- String context(m_rawAttributeBeforeValue.data(), m_rawAttributeBeforeValue.size());
- if (xssAuditor() && !xssAuditor()->canLoadExternalScriptFromSrc(attributeValue))
- attributeValue = blankURL().string();
- }
-
- m_currentToken.addAttribute(m_attrName, attributeValue, inViewSourceMode());
- m_dest = m_buffer;
- state.setTagState(SearchAttribute);
- tquote = NoQuote;
- if (inViewSourceMode())
- m_currentToken.addViewSourceChar(curchar);
- src.advancePastNonNewline();
- break;
- }
- }
-
- *m_dest++ = curchar;
- src.advance(m_lineNumber);
- }
- break;
- case Value:
- while (!src.isEmpty()) {
- checkBuffer();
- UChar curchar = *src;
- if (curchar <= '>' && !src.escaped()) {
- // parse Entities
- if (curchar == '&') {
- src.advancePastNonNewline();
- state = parseEntity(src, m_dest, state, cBufferPos, true, true);
- break;
- }
- // no quotes. Every space means end of value
- // '/' does not delimit in IE!
- if (isASCIISpace(curchar) || curchar == '>') {
- AtomicString attributeValue(m_buffer + 1, m_dest - m_buffer - 1);
-
- if (m_currentToken.beginTag && m_currentToken.tagName == scriptTag && !inViewSourceMode() && !m_treeBuilder->skipMode() && m_attrName == srcAttr) {
- String context(m_rawAttributeBeforeValue.data(), m_rawAttributeBeforeValue.size());
- if (xssAuditor() && !xssAuditor()->canLoadExternalScriptFromSrc(attributeValue))
- attributeValue = blankURL().string();
- }
-
- m_currentToken.addAttribute(m_attrName, attributeValue, inViewSourceMode());
- if (inViewSourceMode())
- m_currentToken.addViewSourceChar('v');
- m_dest = m_buffer;
- state.setTagState(SearchAttribute);
- break;
- }
- }
-
- *m_dest++ = curchar;
- src.advance(m_lineNumber);
- }
- break;
- case SearchEnd:
- {
- while (!src.isEmpty()) {
- UChar ch = *src;
- if (ch == '>' || ch == '<')
- break;
- if (ch == '/')
- m_currentToken.selfClosingTag = true;
- if (inViewSourceMode())
- m_currentToken.addViewSourceChar(ch);
- src.advance(m_lineNumber);
- }
- if (src.isEmpty())
- break;
-
- searchCount = 0; // Stop looking for '<!--' sequence
- state.setTagState(NoTag);
- tquote = NoQuote;
-
- if (*src != '<')
- src.advance(m_lineNumber);
-
- if (m_currentToken.tagName == nullAtom) { //stop if tag is unknown
- m_cBufferPos = cBufferPos;
- return state;
- }
-
- AtomicString tagName = m_currentToken.tagName;
-
- // Handle <script src="foo"/> like Mozilla/Opera. We have to do this now for Dashboard
- // compatibility.
- bool isSelfClosingScript = m_currentToken.selfClosingTag && m_currentToken.beginTag && m_currentToken.tagName == scriptTag;
- bool beginTag = !m_currentToken.selfClosingTag && m_currentToken.beginTag;
- if (m_currentToken.beginTag && m_currentToken.tagName == scriptTag && !inViewSourceMode() && !m_treeBuilder->skipMode()) {
- Attribute* a = 0;
- m_scriptTagSrcAttrValue = String();
- m_scriptTagCharsetAttrValue = String();
- if (m_currentToken.attrs && !m_fragment) {
- if (document()->frame() && document()->frame()->script()->canExecuteScripts(NotAboutToExecuteScript)) {
- if ((a = m_currentToken.attrs->getAttributeItem(srcAttr)))
- m_scriptTagSrcAttrValue = document()->completeURL(deprecatedParseURL(a->value())).string();
- }
- }
- }
-
- RefPtr<Node> n = processToken();
- m_cBufferPos = cBufferPos;
- if (n || inViewSourceMode()) {
- State savedState = state;
- SegmentedString savedSrc = src;
- long savedLineno = m_lineNumber;
- if ((tagName == preTag || tagName == listingTag) && !inViewSourceMode()) {
- if (beginTag)
- state.setDiscardLF(true); // Discard the first LF after we open a pre.
- } else if (tagName == scriptTag) {
- ASSERT(!m_scriptNode);
- m_scriptNode = static_pointer_cast<HTMLScriptElement>(n);
- if (m_scriptNode)
- m_scriptTagCharsetAttrValue = m_scriptNode->scriptCharset();
- if (beginTag) {
- m_searchStopper = scriptEnd;
- m_searchStopperLength = 8;
- state.setInScript(true);
- state = parseNonHTMLText(src, state);
- } else if (isSelfClosingScript) { // Handle <script src="foo"/>
- state.setInScript(true);
- state = scriptHandler(state);
- }
- } else if (tagName == styleTag) {
- if (beginTag) {
- m_searchStopper = styleEnd;
- m_searchStopperLength = 7;
- state.setInStyle(true);
- state = parseNonHTMLText(src, state);
- }
- } else if (tagName == textareaTag) {
- if (beginTag) {
- m_searchStopper = textareaEnd;
- m_searchStopperLength = 10;
- state.setInTextArea(true);
- state = parseNonHTMLText(src, state);
- }
- } else if (tagName == titleTag) {
- if (beginTag) {
- m_searchStopper = titleEnd;
- m_searchStopperLength = 7;
- state.setInTitle(true);
- state = parseNonHTMLText(src, state);
- }
- } else if (tagName == xmpTag) {
- if (beginTag) {
- m_searchStopper = xmpEnd;
- m_searchStopperLength = 5;
- state.setInXmp(true);
- state = parseNonHTMLText(src, state);
- }
- } else if (tagName == iframeTag) {
- if (beginTag) {
- m_searchStopper = iframeEnd;
- m_searchStopperLength = 8;
- state.setInIFrame(true);
- state = parseNonHTMLText(src, state);
- }
- }
- if (src.isEmpty() && (state.inTitle() || inViewSourceMode()) && !state.inComment() && !(state.inScript() && m_currentScriptTagStartLineNumber)) {
- // We just ate the rest of the document as the #text node under the special tag!
- // Reset the state then retokenize without special handling.
- // Let the parser clean up the missing close tag.
- // FIXME: This is incorrect, because src.isEmpty() doesn't mean we're
- // at the end of the document unless m_noMoreData is also true. We need
- // to detect this case elsewhere, and save the state somewhere other
- // than a local variable.
- state = savedState;
- src = savedSrc;
- m_lineNumber = savedLineno;
- m_scriptCodeSize = 0;
- }
- }
- if (tagName == plaintextTag)
- state.setInPlainText(beginTag);
- return state; // Finished parsing tag!
- }
- } // end switch
- }
- m_cBufferPos = cBufferPos;
- return state;
-}
-
-inline bool LegacyHTMLDocumentParser::continueProcessing(int& processedCount, double startTime, State &state)
-{
- // We don't want to be checking elapsed time with every character, so we only check after we've
- // processed a certain number of characters.
- bool allowedYield = state.allowYield();
- state.setAllowYield(false);
- if (!state.loadingExtScript() && !state.forceSynchronous() && !m_executingScript && (processedCount > m_tokenizerChunkSize || allowedYield)) {
- processedCount = 0;
- if (currentTime() - startTime > m_tokenizerTimeDelay) {
- /* FIXME: We'd like to yield aggressively to give stylesheets the opportunity to
- load, but this hurts overall performance on slower machines. For now turn this
- off.
- || (!document()->haveStylesheetsLoaded() &&
- (document()->documentElement()->id() != ID_HTML || document()->body()))) {*/
- // Schedule the timer to keep processing as soon as possible.
- m_timer.startOneShot(0);
- return false;
- }
- }
-
- processedCount++;
- return true;
-}
-
-// Turns the statemachine one crank using the passed in State object.
-// This does not modify m_state directly in order to be reentrant.
-ALWAYS_INLINE void LegacyHTMLDocumentParser::advance(State& state)
-{
- // do we need to enlarge the buffer?
- checkBuffer();
-
- UChar cc = *m_src;
-
- bool wasSkipLF = state.skipLF();
- if (wasSkipLF)
- state.setSkipLF(false);
-
- if (wasSkipLF && (cc == '\n'))
- m_src.advance();
- else if (state.needsSpecialWriteHandling()) {
- // it's important to keep needsSpecialWriteHandling with the flags this block tests
- if (state.hasEntityState())
- state = parseEntity(m_src, m_dest, state, m_cBufferPos, false, state.hasTagState());
- else if (state.inPlainText())
- state = parseText(m_src, state);
- else if (state.inAnyNonHTMLText())
- state = parseNonHTMLText(m_src, state);
- else if (state.inComment())
- state = parseComment(m_src, state);
- else if (state.inDoctype())
- state = parseDoctype(m_src, state);
- else if (state.inServer())
- state = parseServer(m_src, state);
- else if (state.inProcessingInstruction())
- state = parseProcessingInstruction(m_src, state);
- else if (state.hasTagState())
- state = parseTag(m_src, state);
- else if (state.startTag()) {
- state.setStartTag(false);
-
- switch (cc) {
- case '/':
- break;
- case '!': {
- // <!-- comment --> or <!DOCTYPE ...>
- searchCount = 1; // Look for '<!--' sequence to start comment or '<!DOCTYPE' sequence to start doctype
- m_doctypeSearchCount = 1;
- break;
- }
- case '?': {
- // xml processing instruction
- state.setInProcessingInstruction(true);
- tquote = NoQuote;
- state = parseProcessingInstruction(m_src, state);
- return;
- }
- case '%':
- if (!m_brokenServer) {
- // <% server stuff, handle as comment %>
- state.setInServer(true);
- tquote = NoQuote;
- state = parseServer(m_src, state);
- return;
- }
- // else fall through
- default: {
- if (((cc >= 'a') && (cc <= 'z')) || ((cc >= 'A') && (cc <= 'Z'))) {
- // Start of a Start-Tag
- } else {
- // Invalid tag
- // Add as is
- *m_dest = '<';
- m_dest++;
- return;
- }
- }
- }; // end case
-
- processToken();
-
- m_cBufferPos = 0;
- state.setTagState(TagName);
- state = parseTag(m_src, state);
- }
- } else if (cc == '&' && !m_src.escaped()) {
- m_src.advancePastNonNewline();
- state = parseEntity(m_src, m_dest, state, m_cBufferPos, true, state.hasTagState());
- } else if (cc == '<' && !m_src.escaped()) {
- m_currentTagStartLineNumber = m_lineNumber;
- m_src.advancePastNonNewline();
- state.setStartTag(true);
- state.setDiscardLF(false);
- } else if (cc == '\n' || cc == '\r') {
- if (state.discardLF())
- // Ignore this LF
- state.setDiscardLF(false); // We have discarded 1 LF
- else {
- // Process this LF
- *m_dest++ = '\n';
- if (cc == '\r' && !m_src.excludeLineNumbers())
- m_lineNumber++;
- }
-
- /* Check for MS-DOS CRLF sequence */
- if (cc == '\r')
- state.setSkipLF(true);
- m_src.advance(m_lineNumber);
- } else {
- state.setDiscardLF(false);
- *m_dest++ = cc;
- m_src.advancePastNonNewline();
- }
-}
-
-void LegacyHTMLDocumentParser::willWriteHTML(const SegmentedString& source)
-{
- #if ENABLE(INSPECTOR)
- if (InspectorTimelineAgent* timelineAgent = document()->inspectorTimelineAgent())
- timelineAgent->willWriteHTML(source.length(), m_lineNumber);
- #endif
-}
-
-void LegacyHTMLDocumentParser::didWriteHTML()
-{
- #if ENABLE(INSPECTOR)
- if (InspectorTimelineAgent* timelineAgent = document()->inspectorTimelineAgent())
- timelineAgent->didWriteHTML(m_lineNumber);
- #endif
-}
-
-void LegacyHTMLDocumentParser::write(const SegmentedString& str, bool appendData)
-{
- if (!m_buffer)
- return;
-
- if (m_parserStopped)
- return;
-
- SegmentedString source(str);
- if (m_executingScript)
- source.setExcludeLineNumbers();
-
- if ((m_executingScript && appendData) || !m_pendingScripts.isEmpty()) {
- // don't parse; we will do this later
- if (m_currentPrependingSrc)
- m_currentPrependingSrc->append(source);
- else {
- m_pendingSrc.append(source);
-#if PRELOAD_SCANNER_ENABLED
- if (m_preloadScanner && m_preloadScanner->inProgress() && appendData)
- m_preloadScanner->write(source);
-#endif
- }
- return;
- }
-
-#if PRELOAD_SCANNER_ENABLED
- if (m_preloadScanner && m_preloadScanner->inProgress() && appendData)
- m_preloadScanner->end();
-#endif
-
- if (!m_src.isEmpty())
- m_src.append(source);
- else
- setSrc(source);
-
- // Once a timer is set, it has control of when the parser continues.
- if (m_timer.isActive())
- return;
-
- bool wasInWrite = m_inWrite;
- m_inWrite = true;
-
- willWriteHTML(source);
-
- Frame* frame = document()->frame();
- State state = m_state;
- int processedCount = 0;
- double startTime = currentTime();
-
- while (!m_src.isEmpty() && (!frame || !frame->redirectScheduler()->locationChangePending())) {
- if (!continueProcessing(processedCount, startTime, state))
- break;
- advance(state);
- }
-
- didWriteHTML();
-
- m_inWrite = wasInWrite;
- m_state = state;
-
- if (m_noMoreData && !m_inWrite && !state.loadingExtScript() && !m_executingScript && !m_timer.isActive())
- end(); // this actually causes us to be deleted
-
- // After parsing, go ahead and dispatch image beforeload events, but only if we're doing
- // document parsing. For document fragments we wait, since they'll likely end up in the document by the time
- // the beforeload events fire.
- if (!m_fragment)
- ImageLoader::dispatchPendingBeforeLoadEvents();
-}
-
-void LegacyHTMLDocumentParser::insert(const SegmentedString& source)
-{
- // FIXME: forceSynchronous should always be the same as the bool passed to
- // write(). However LegacyHTMLDocumentParser uses write("", false) to pump
- // the parser (after running external scripts, etc.) thus necessitating a
- // separate state for forceSynchronous.
- bool wasForcedSynchronous = forceSynchronous();
- setForceSynchronous(true);
- write(source, false);
- setForceSynchronous(wasForcedSynchronous);
-}
-
-void LegacyHTMLDocumentParser::append(const SegmentedString& source)
-{
- write(source, true);
-}
-
-void LegacyHTMLDocumentParser::stopParsing()
-{
- DocumentParser::stopParsing();
- m_timer.stop();
-
- // FIXME: Why is LegacyHTMLDocumentParser the only DocumentParser which calls checkCompleted?
- // The FrameLoader needs to know that the parser has finished with its data,
- // regardless of whether it happened naturally or due to manual intervention.
- if (!m_fragment && document()->frame())
- document()->frame()->loader()->checkCompleted();
-}
-
-bool LegacyHTMLDocumentParser::processingData() const
-{
- return m_timer.isActive() || m_inWrite;
-}
-
-void LegacyHTMLDocumentParser::timerFired(Timer<LegacyHTMLDocumentParser>*)
-{
- if (document()->view() && document()->view()->layoutPending() && !document()->minimumLayoutDelay()) {
- // Restart the timer and let layout win. This is basically a way of ensuring that the layout
- // timer has higher priority than our timer.
- m_timer.startOneShot(0);
- return;
- }
-
- // Invoke write() as though more data came in. This might cause us to get deleted.
- write(SegmentedString(), true);
-}
-
-void LegacyHTMLDocumentParser::end()
-{
- ASSERT(!m_timer.isActive());
- m_timer.stop(); // Only helps if assertion above fires, but do it anyway.
-
- if (m_buffer) {
- // parseTag is using the buffer for different matters
- if (!m_state.hasTagState())
- processToken();
-
- fastFree(m_scriptCode);
- m_scriptCode = 0;
- m_scriptCodeSize = m_scriptCodeCapacity = m_scriptCodeResync = 0;
-
- fastFree(m_buffer);
- m_buffer = 0;
- }
-
- if (!inViewSourceMode())
- m_treeBuilder->finished();
- else
- document()->finishedParsing();
-}
-
-void LegacyHTMLDocumentParser::finish()
-{
- // do this as long as we don't find matching comment ends
- while ((m_state.inComment() || m_state.inServer()) && m_scriptCode && m_scriptCodeSize) {
- // we've found an unmatched comment start
- if (m_state.inComment())
- m_brokenComments = true;
- else
- m_brokenServer = true;
- checkScriptBuffer();
- m_scriptCode[m_scriptCodeSize] = 0;
- m_scriptCode[m_scriptCodeSize + 1] = 0;
- int pos;
- String food;
- if (m_state.inScript() || m_state.inStyle() || m_state.inTextArea())
- food = String(m_scriptCode, m_scriptCodeSize);
- else if (m_state.inServer()) {
- food = "<";
- food.append(m_scriptCode, m_scriptCodeSize);
- } else {
- pos = find(m_scriptCode, m_scriptCodeSize, '>');
- food = String(m_scriptCode + pos + 1, m_scriptCodeSize - pos - 1);
- }
- fastFree(m_scriptCode);
- m_scriptCode = 0;
- m_scriptCodeSize = m_scriptCodeCapacity = m_scriptCodeResync = 0;
- m_state.setInComment(false);
- m_state.setInServer(false);
- if (!food.isEmpty())
- write(food, true);
- }
- // this indicates we will not receive any more data... but if we are waiting on
- // an external script to load, we can't finish parsing until that is done
- m_noMoreData = true;
- if (!m_inWrite && !m_state.loadingExtScript() && !m_executingScript && !m_timer.isActive())
- end(); // this actually causes us to be deleted
-}
-
-bool LegacyHTMLDocumentParser::finishWasCalled()
-{
- return m_noMoreData;
-}
-
-PassRefPtr<Node> LegacyHTMLDocumentParser::processToken()
-{
- if (m_dest > m_buffer) {
- m_currentToken.text = StringImpl::createStrippingNullCharacters(m_buffer, m_dest - m_buffer);
- if (m_currentToken.tagName != commentAtom)
- m_currentToken.tagName = textAtom;
- } else if (m_currentToken.tagName == nullAtom) {
- m_currentToken.reset();
- return 0;
- }
-
- m_dest = m_buffer;
-
- RefPtr<Node> n;
-
- if (!m_parserStopped) {
- if (NamedNodeMap* map = m_currentToken.attrs.get())
- map->shrinkToLength();
- if (inViewSourceMode())
- static_cast<HTMLViewSourceDocument*>(document())->addViewSourceToken(&m_currentToken);
- else
- // pass the token over to the parser, the parser DOES NOT delete the token
- n = m_treeBuilder->parseToken(&m_currentToken);
- }
- m_currentToken.reset();
-
- return n.release();
-}
-
-void LegacyHTMLDocumentParser::processDoctypeToken()
-{
- if (inViewSourceMode())
- static_cast<HTMLViewSourceDocument*>(document())->addViewSourceDoctypeToken(&m_doctypeToken);
- else
- m_treeBuilder->parseDoctypeToken(&m_doctypeToken);
-}
-
-LegacyHTMLDocumentParser::~LegacyHTMLDocumentParser()
-{
- ASSERT(!m_inWrite);
- reset();
-}
-
-
-void LegacyHTMLDocumentParser::enlargeBuffer(int len)
-{
- // Resize policy: Always at least double the size of the buffer each time.
- int delta = max(len, m_bufferSize);
-
- // Check for overflow.
- // For now, handle overflow the same way we handle fastRealloc failure, with CRASH.
- static const int maxSize = INT_MAX / sizeof(UChar);
- if (delta > maxSize - m_bufferSize)
- CRASH();
-
- int newSize = m_bufferSize + delta;
- int oldOffset = m_dest - m_buffer;
- m_buffer = static_cast<UChar*>(fastRealloc(m_buffer, newSize * sizeof(UChar)));
- m_dest = m_buffer + oldOffset;
- m_bufferSize = newSize;
-}
-
-void LegacyHTMLDocumentParser::enlargeScriptBuffer(int len)
-{
- // Resize policy: Always at least double the size of the buffer each time.
- int delta = max(len, m_scriptCodeCapacity);
-
- // Check for overflow.
- // For now, handle overflow the same way we handle fastRealloc failure, with CRASH.
- static const int maxSize = INT_MAX / sizeof(UChar);
- if (delta > maxSize - m_scriptCodeCapacity)
- CRASH();
-
- int newSize = m_scriptCodeCapacity + delta;
- // If we allow fastRealloc(ptr, 0), it will call CRASH(). We run into this
- // case if the HTML being parsed begins with "<!--" and there's more data
- // coming.
- if (!newSize) {
- ASSERT(!m_scriptCode);
- return;
- }
-
- m_scriptCode = static_cast<UChar*>(fastRealloc(m_scriptCode, newSize * sizeof(UChar)));
- m_scriptCodeCapacity = newSize;
-}
-
-void LegacyHTMLDocumentParser::executeScriptsWaitingForStylesheets()
-{
- ASSERT(document()->haveStylesheetsLoaded());
-
- if (m_hasScriptsWaitingForStylesheets)
- notifyFinished(0);
-}
-
-void LegacyHTMLDocumentParser::notifyFinished(CachedResource*)
-{
- executeExternalScriptsIfReady();
-}
-
-void LegacyHTMLDocumentParser::executeExternalScriptsIfReady()
-{
- ASSERT(!m_pendingScripts.isEmpty());
-
- // Make external scripts wait for external stylesheets.
- // FIXME: This needs to be done for inline scripts too.
- m_hasScriptsWaitingForStylesheets = !document()->haveStylesheetsLoaded();
- if (m_hasScriptsWaitingForStylesheets)
- return;
-
- bool finished = false;
-
- double startTime = currentTime();
- while (!finished && m_pendingScripts.first()->isLoaded()) {
- if (!continueExecutingExternalScripts(startTime))
- break;
-
- CachedResourceHandle<CachedScript> cs = m_pendingScripts.takeFirst();
- ASSERT(cache()->disabled() || cs->accessCount() > 0);
-
- setSrc(SegmentedString());
-
- // make sure we forget about the script before we execute the new one
- // infinite recursion might happen otherwise
- ScriptSourceCode sourceCode(cs.get());
- bool errorOccurred = cs->errorOccurred();
- cs->removeClient(this);
-
- RefPtr<Node> n = m_scriptNode.release();
-
- if (errorOccurred)
- n->dispatchEvent(Event::create(eventNames().errorEvent, true, false));
- else {
- if (static_cast<HTMLScriptElement*>(n.get())->shouldExecuteAsJavaScript())
- m_state = scriptExecution(sourceCode, m_state);
-#if ENABLE(XHTMLMP)
- else
- document()->setShouldProcessNoscriptElement(true);
-#endif
- n->dispatchEvent(Event::create(eventNames().loadEvent, false, false));
- }
-
- // The state of m_pendingScripts.isEmpty() can change inside the scriptExecution()
- // call above, so test afterwards.
- finished = m_pendingScripts.isEmpty();
- if (finished) {
- ASSERT(!m_hasScriptsWaitingForStylesheets);
- m_state.setLoadingExtScript(false);
- } else if (m_hasScriptsWaitingForStylesheets) {
- // m_hasScriptsWaitingForStylesheets flag might have changed during the script execution.
- // If it did we are now blocked waiting for stylesheets and should not execute more scripts until they arrive.
- finished = true;
- }
-
- // 'm_requestingScript' is true when we are called synchronously from
- // scriptHandler(). In that case scriptHandler() will take care
- // of m_pendingSrc.
- if (!m_requestingScript) {
- SegmentedString rest = m_pendingSrc;
- m_pendingSrc.clear();
- write(rest, false);
- // we might be deleted at this point, do not access any members.
- }
- }
-}
-
-void LegacyHTMLDocumentParser::executeExternalScriptsTimerFired(Timer<LegacyHTMLDocumentParser>*)
-{
- if (document()->view() && document()->view()->layoutPending() && !document()->minimumLayoutDelay()) {
- // Restart the timer and do layout first.
- m_externalScriptsTimer.startOneShot(0);
- return;
- }
-
- // Continue executing external scripts.
- executeExternalScriptsIfReady();
-}
-
-bool LegacyHTMLDocumentParser::continueExecutingExternalScripts(double startTime)
-{
- if (m_externalScriptsTimer.isActive())
- return false;
-
- if (currentTime() - startTime > m_tokenizerTimeDelay) {
- // Schedule the timer to keep processing as soon as possible.
- m_externalScriptsTimer.startOneShot(0);
- return false;
- }
- return true;
-}
-
-bool LegacyHTMLDocumentParser::isWaitingForScripts() const
-{
- return m_state.loadingExtScript();
-}
-
-void LegacyHTMLDocumentParser::setSrc(const SegmentedString& source)
-{
- m_src = source;
-}
-
-void LegacyHTMLDocumentParser::parseDocumentFragment(const String& source, DocumentFragment* fragment, FragmentScriptingPermission scriptingPermission)
-{
- LegacyHTMLDocumentParser parser(fragment, scriptingPermission);
- parser.setForceSynchronous(true);
- parser.write(source, true);
- parser.finish();
- ASSERT(!parser.processingData()); // make sure we're done (see 3963151)
-}
-
-UChar decodeNamedEntity(const char* name)
-{
- const Entity* e = findEntity(name, strlen(name));
- return e ? e->code : 0;
-}
-
-}
diff --git a/WebCore/html/LegacyHTMLDocumentParser.h b/WebCore/html/LegacyHTMLDocumentParser.h
deleted file mode 100644
index 49e6976..0000000
--- a/WebCore/html/LegacyHTMLDocumentParser.h
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- Copyright (C) 1997 Martin Jones (mjones@kde.org)
- (C) 1997 Torben Weis (weis@kde.org)
- (C) 1998 Waldo Bastian (bastian@kde.org)
- (C) 2001 Dirk Mueller (mueller@kde.org)
- Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public License
- along with this library; see the file COPYING.LIB. If not, write to
- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-#ifndef LegacyHTMLDocumentParser_h
-#define LegacyHTMLDocumentParser_h
-
-#include "CachedResourceClient.h"
-#include "CachedResourceHandle.h"
-#include "FragmentScriptingPermission.h"
-#include "NamedNodeMap.h"
-#include "ScriptableDocumentParser.h"
-#include "SegmentedString.h"
-#include "Timer.h"
-#include <wtf/Deque.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-class CachedScript;
-class DocumentFragment;
-class Document;
-class HTMLDocument;
-class HTMLScriptElement;
-class HTMLViewSourceDocument;
-class FrameView;
-class LegacyHTMLTreeBuilder;
-class Node;
-class LegacyPreloadScanner;
-class ScriptSourceCode;
-
-/**
- * @internal
- * represents one HTML tag. Consists of a numerical id, and the list
- * of attributes. Can also represent text. In this case the id = 0 and
- * text contains the text.
- */
-struct Token {
- Token()
- : beginTag(true)
- , selfClosingTag(false)
- , brokenXMLStyle(false)
- , m_sourceInfo(0)
- { }
- ~Token() { }
-
- void addAttribute(AtomicString& attrName, const AtomicString& v, bool viewSourceMode);
-
- bool isOpenTag(const QualifiedName& fullName) const { return beginTag && fullName.localName() == tagName; }
- bool isCloseTag(const QualifiedName& fullName) const { return !beginTag && fullName.localName() == tagName; }
-
- void reset()
- {
- attrs = 0;
- text = 0;
- tagName = nullAtom;
- beginTag = true;
- selfClosingTag = false;
- brokenXMLStyle = false;
- if (m_sourceInfo)
- m_sourceInfo->clear();
- }
-
- void addViewSourceChar(UChar c) { if (!m_sourceInfo.get()) m_sourceInfo.set(new Vector<UChar>); m_sourceInfo->append(c); }
-
- RefPtr<NamedNodeMap> attrs;
- RefPtr<StringImpl> text;
- AtomicString tagName;
- bool beginTag;
- bool selfClosingTag;
- bool brokenXMLStyle;
- OwnPtr<Vector<UChar> > m_sourceInfo;
-};
-
-enum DoctypeState {
- DoctypeBegin,
- DoctypeBeforeName,
- DoctypeName,
- DoctypeAfterName,
- DoctypeBeforePublicID,
- DoctypePublicID,
- DoctypeAfterPublicID,
- DoctypeBeforeSystemID,
- DoctypeSystemID,
- DoctypeAfterSystemID,
- DoctypeBogus
-};
-
-class DoctypeToken {
-public:
- DoctypeToken() {}
-
- void reset()
- {
- m_name.clear();
- m_publicID.clear();
- m_systemID.clear();
- m_state = DoctypeBegin;
- m_source.clear();
- m_forceQuirks = false;
- }
-
- DoctypeState state() { return m_state; }
- void setState(DoctypeState s) { m_state = s; }
-
- Vector<UChar> m_name;
- Vector<UChar> m_publicID;
- Vector<UChar> m_systemID;
- DoctypeState m_state;
-
- Vector<UChar> m_source;
-
- bool m_forceQuirks; // Used by the HTML5 parser.
-};
-
-//-----------------------------------------------------------------------------
-
-// FIXME: This class does too much. Right now it is both an HTML tokenizer as well
-// as handling all of the non-tokenizer-specific junk related to tokenizing HTML
-// (like dealing with <script> tags). The HTML tokenizer bits should be pushed
-// down into a separate HTML tokenizer class.
-
-class LegacyHTMLDocumentParser : public ScriptableDocumentParser, public CachedResourceClient {
-public:
- LegacyHTMLDocumentParser(HTMLDocument*, bool reportErrors);
- LegacyHTMLDocumentParser(HTMLViewSourceDocument*);
- LegacyHTMLDocumentParser(DocumentFragment*, FragmentScriptingPermission = FragmentScriptingAllowed);
- virtual ~LegacyHTMLDocumentParser();
-
- bool forceSynchronous() const { return m_state.forceSynchronous(); }
- void setForceSynchronous(bool force);
-
- static void parseDocumentFragment(const String&, DocumentFragment*, FragmentScriptingPermission = FragmentScriptingAllowed);
-
-protected:
- // Exposed for FTPDirectoryDocumentParser
- virtual void insert(const SegmentedString&);
- virtual void finish();
-
-private:
- // ScriptableDocumentParser
- virtual void append(const SegmentedString&);
- virtual bool finishWasCalled();
- virtual bool isWaitingForScripts() const;
- virtual void stopParsing();
- virtual bool processingData() const;
- virtual bool isExecutingScript() const { return !!m_executingScript; }
-
- virtual int lineNumber() const { return m_lineNumber; }
- virtual int columnNumber() const { return 1; }
-
- virtual bool processingContentWrittenByScript() const { return m_src.excludeLineNumbers(); }
-
- virtual void executeScriptsWaitingForStylesheets();
-
- virtual LegacyHTMLTreeBuilder* htmlTreeBuilder() const { return m_treeBuilder.get(); }
-
- class State;
-
- void begin();
- void end();
- void reset();
-
- void willWriteHTML(const SegmentedString&);
- void write(const SegmentedString&, bool appendData);
- ALWAYS_INLINE void advance(State&);
- void didWriteHTML();
-
- PassRefPtr<Node> processToken();
- void processDoctypeToken();
-
- State processListing(SegmentedString, State);
- State parseComment(SegmentedString&, State);
- State parseDoctype(SegmentedString&, State);
- State parseServer(SegmentedString&, State);
- State parseText(SegmentedString&, State);
- State parseNonHTMLText(SegmentedString&, State);
- State parseTag(SegmentedString&, State);
- State parseEntity(SegmentedString&, UChar*& dest, State, unsigned& cBufferPos, bool start, bool parsingTag);
- State parseProcessingInstruction(SegmentedString&, State);
- State scriptHandler(State);
- State scriptExecution(const ScriptSourceCode&, State);
- void setSrc(const SegmentedString&);
-
- // check if we have enough space in the buffer.
- // if not enlarge it
- inline void checkBuffer(int len = 10)
- {
- if ((m_dest - m_buffer) > m_bufferSize - len)
- enlargeBuffer(len);
- }
-
- inline void checkScriptBuffer(int len = 10)
- {
- if (m_scriptCodeSize + len >= m_scriptCodeCapacity)
- enlargeScriptBuffer(len);
- }
-
- void enlargeBuffer(int len);
- void enlargeScriptBuffer(int len);
-
- bool continueProcessing(int& processedCount, double startTime, State&);
- void timerFired(Timer<LegacyHTMLDocumentParser>*);
- void allDataProcessed();
-
- // from CachedResourceClient
- void notifyFinished(CachedResource*);
-
- void executeExternalScriptsIfReady();
- void executeExternalScriptsTimerFired(Timer<LegacyHTMLDocumentParser>*);
- bool continueExecutingExternalScripts(double startTime);
-
- // Internal buffers
- ///////////////////
- UChar* m_buffer;
- int m_bufferSize;
- UChar* m_dest;
-
- Token m_currentToken;
-
- // This buffer holds the raw characters we've seen between the beginning of
- // the attribute name and the first character of the attribute value.
- Vector<UChar, 32> m_rawAttributeBeforeValue;
-
- // DocumentParser flags
- //////////////////
- // are we in quotes within a html tag
- enum { NoQuote, SingleQuote, DoubleQuote } tquote;
-
- // Are we in a &... character entity description?
- enum EntityState {
- NoEntity = 0,
- SearchEntity = 1,
- NumericSearch = 2,
- Hexadecimal = 3,
- Decimal = 4,
- EntityName = 5,
- SearchSemicolon = 6
- };
- unsigned EntityUnicodeValue;
-
- enum TagState {
- NoTag = 0,
- TagName = 1,
- SearchAttribute = 2,
- AttributeName = 3,
- SearchEqual = 4,
- SearchValue = 5,
- QuotedValue = 6,
- Value = 7,
- SearchEnd = 8
- };
-
- class State {
- public:
- State() : m_bits(0) { }
-
- TagState tagState() const { return static_cast<TagState>(m_bits & TagMask); }
- void setTagState(TagState t) { m_bits = (m_bits & ~TagMask) | t; }
- EntityState entityState() const { return static_cast<EntityState>((m_bits & EntityMask) >> EntityShift); }
- void setEntityState(EntityState e) { m_bits = (m_bits & ~EntityMask) | (e << EntityShift); }
-
- bool inScript() const { return testBit(InScript); }
- void setInScript(bool v) { setBit(InScript, v); }
- bool inStyle() const { return testBit(InStyle); }
- void setInStyle(bool v) { setBit(InStyle, v); }
- bool inXmp() const { return testBit(InXmp); }
- void setInXmp(bool v) { setBit(InXmp, v); }
- bool inTitle() const { return testBit(InTitle); }
- void setInTitle(bool v) { setBit(InTitle, v); }
- bool inIFrame() const { return testBit(InIFrame); }
- void setInIFrame(bool v) { setBit(InIFrame, v); }
- bool inPlainText() const { return testBit(InPlainText); }
- void setInPlainText(bool v) { setBit(InPlainText, v); }
- bool inProcessingInstruction() const { return testBit(InProcessingInstruction); }
- void setInProcessingInstruction(bool v) { return setBit(InProcessingInstruction, v); }
- bool inComment() const { return testBit(InComment); }
- void setInComment(bool v) { setBit(InComment, v); }
- bool inDoctype() const { return testBit(InDoctype); }
- void setInDoctype(bool v) { setBit(InDoctype, v); }
- bool inTextArea() const { return testBit(InTextArea); }
- void setInTextArea(bool v) { setBit(InTextArea, v); }
- bool escaped() const { return testBit(Escaped); }
- void setEscaped(bool v) { setBit(Escaped, v); }
- bool inServer() const { return testBit(InServer); }
- void setInServer(bool v) { setBit(InServer, v); }
- bool skipLF() const { return testBit(SkipLF); }
- void setSkipLF(bool v) { setBit(SkipLF, v); }
- bool startTag() const { return testBit(StartTag); }
- void setStartTag(bool v) { setBit(StartTag, v); }
- bool discardLF() const { return testBit(DiscardLF); }
- void setDiscardLF(bool v) { setBit(DiscardLF, v); }
- bool allowYield() const { return testBit(AllowYield); }
- void setAllowYield(bool v) { setBit(AllowYield, v); }
- bool loadingExtScript() const { return testBit(LoadingExtScript); }
- void setLoadingExtScript(bool v) { setBit(LoadingExtScript, v); }
- bool forceSynchronous() const { return testBit(ForceSynchronous); }
- void setForceSynchronous(bool v) { setBit(ForceSynchronous, v); }
-
- bool inAnyNonHTMLText() const { return m_bits & (InScript | InStyle | InXmp | InTextArea | InTitle | InIFrame); }
- bool hasTagState() const { return m_bits & TagMask; }
- bool hasEntityState() const { return m_bits & EntityMask; }
-
- bool needsSpecialWriteHandling() const { return m_bits & (InScript | InStyle | InXmp | InTextArea | InTitle | InIFrame | TagMask | EntityMask | InPlainText | InComment | InDoctype | InServer | InProcessingInstruction | StartTag); }
-
- private:
- static const int EntityShift = 4;
- enum StateBits {
- TagMask = (1 << 4) - 1,
- EntityMask = (1 << 7) - (1 << 4),
- InScript = 1 << 7,
- InStyle = 1 << 8,
- // Bit 9 unused
- InXmp = 1 << 10,
- InTitle = 1 << 11,
- InPlainText = 1 << 12,
- InProcessingInstruction = 1 << 13,
- InComment = 1 << 14,
- InTextArea = 1 << 15,
- Escaped = 1 << 16,
- InServer = 1 << 17,
- SkipLF = 1 << 18,
- StartTag = 1 << 19,
- DiscardLF = 1 << 20, // FIXME: should clarify difference between skip and discard
- AllowYield = 1 << 21,
- LoadingExtScript = 1 << 22,
- ForceSynchronous = 1 << 23,
- InIFrame = 1 << 24,
- InDoctype = 1 << 25
- };
-
- void setBit(StateBits bit, bool value)
- {
- if (value)
- m_bits |= bit;
- else
- m_bits &= ~bit;
- }
- bool testBit(StateBits bit) const { return m_bits & bit; }
-
- unsigned m_bits;
- };
-
- State m_state;
-
- DoctypeToken m_doctypeToken;
- int m_doctypeSearchCount;
- int m_doctypeSecondarySearchCount;
-
- bool m_brokenServer;
-
- // Name of an attribute that we just scanned.
- AtomicString m_attrName;
-
- // Used to store the code of a scripting sequence
- UChar* m_scriptCode;
- // Size of the script sequenze stored in @ref #scriptCode
- int m_scriptCodeSize;
- // Maximal size that can be stored in @ref #scriptCode
- int m_scriptCodeCapacity;
- // resync point of script code size
- int m_scriptCodeResync;
-
- // Stores characters if we are scanning for a string like "</script>"
- UChar searchBuffer[10];
-
- // Counts where we are in the string we are scanning for
- int searchCount;
- // the stopper string
- const char* m_searchStopper;
- int m_searchStopperLength;
-
- // if no more data is coming, just parse what we have (including ext scripts that
- // may be still downloading) and finish
- bool m_noMoreData;
- // URL to get source code of script from
- String m_scriptTagSrcAttrValue;
- String m_scriptTagCharsetAttrValue;
- // the HTML code we will parse after the external script we are waiting for has loaded
- SegmentedString m_pendingSrc;
-
- // the HTML code we will parse after this particular script has
- // loaded, but before all pending HTML
- SegmentedString* m_currentPrependingSrc;
-
- // true if we are executing a script while parsing a document. This causes the parsing of
- // the output of the script to be postponed until after the script has finished executing
- int m_executingScript;
- Deque<CachedResourceHandle<CachedScript> > m_pendingScripts;
- RefPtr<HTMLScriptElement> m_scriptNode;
-
- bool m_requestingScript;
- bool m_hasScriptsWaitingForStylesheets;
-
- // if we found one broken comment, there are most likely others as well
- // store a flag to get rid of the O(n^2) behaviour in such a case.
- bool m_brokenComments;
- // current line number
- int m_lineNumber;
- int m_currentScriptTagStartLineNumber;
- int m_currentTagStartLineNumber;
-
- double m_tokenizerTimeDelay;
- int m_tokenizerChunkSize;
-
- // The timer for continued processing.
- Timer<LegacyHTMLDocumentParser> m_timer;
-
- // The timer for continued executing external scripts.
- Timer<LegacyHTMLDocumentParser> m_externalScriptsTimer;
-
-// This buffer can hold arbitrarily long user-defined attribute names, such as in EMBED tags.
-// So any fixed number might be too small, but rather than rewriting all usage of this buffer
-// we'll just make it large enough to handle all imaginable cases.
-#define CBUFLEN 1024
- UChar m_cBuffer[CBUFLEN + 2];
- unsigned int m_cBufferPos;
-
- SegmentedString m_src;
- OwnPtr<LegacyHTMLTreeBuilder> m_treeBuilder;
- bool m_inWrite;
- bool m_fragment;
- FragmentScriptingPermission m_scriptingPermission;
-
- OwnPtr<LegacyPreloadScanner> m_preloadScanner;
-};
-
-UChar decodeNamedEntity(const char*);
-
-} // namespace WebCore
-
-#endif // LegacyHTMLDocumentParser_h
diff --git a/WebCore/html/LegacyHTMLTreeBuilder.cpp b/WebCore/html/LegacyHTMLTreeBuilder.cpp
index ee0bcfc..f39579c 100644
--- a/WebCore/html/LegacyHTMLTreeBuilder.cpp
+++ b/WebCore/html/LegacyHTMLTreeBuilder.cpp
@@ -52,9 +52,9 @@
#include "HTMLTableCellElement.h"
#include "HTMLTableRowElement.h"
#include "HTMLTableSectionElement.h"
-#include "LegacyHTMLDocumentParser.h"
#include "LocalizedStrings.h"
#include "Page.h"
+#include "ScriptableDocumentParser.h"
#include "Settings.h"
#include "Text.h"
#include "TreeDepthLimit.h"
diff --git a/WebCore/html/LegacyHTMLTreeBuilder.h b/WebCore/html/LegacyHTMLTreeBuilder.h
index 4ac8413..ed2b857 100644
--- a/WebCore/html/LegacyHTMLTreeBuilder.h
+++ b/WebCore/html/LegacyHTMLTreeBuilder.h
@@ -26,6 +26,7 @@
#include "FragmentScriptingPermission.h"
#include "HTMLParserErrorCodes.h"
+#include "NamedNodeMap.h"
#include "QualifiedName.h"
#include <wtf/Forward.h>
#include <wtf/OwnPtr.h>
@@ -44,7 +45,97 @@ class HTMLParserQuirks;
class Node;
struct HTMLStackElem;
-struct Token;
+
+/**
+ * @internal
+ * represents one HTML tag. Consists of a numerical id, and the list
+ * of attributes. Can also represent text. In this case the id = 0 and
+ * text contains the text.
+ */
+struct Token {
+ Token()
+ : beginTag(true)
+ , selfClosingTag(false)
+ , brokenXMLStyle(false)
+ , m_sourceInfo(0)
+ { }
+ ~Token() { }
+
+ void addAttribute(AtomicString& attrName, const AtomicString& v, bool viewSourceMode);
+
+ bool isOpenTag(const QualifiedName& fullName) const { return beginTag && fullName.localName() == tagName; }
+ bool isCloseTag(const QualifiedName& fullName) const { return !beginTag && fullName.localName() == tagName; }
+
+ void reset()
+ {
+ attrs = 0;
+ text = 0;
+ tagName = nullAtom;
+ beginTag = true;
+ selfClosingTag = false;
+ brokenXMLStyle = false;
+ if (m_sourceInfo)
+ m_sourceInfo->clear();
+ }
+
+ void addViewSourceChar(UChar c)
+ {
+ if (!m_sourceInfo.get())
+ m_sourceInfo.set(new Vector<UChar>);
+ m_sourceInfo->append(c);
+ }
+
+ RefPtr<NamedNodeMap> attrs;
+ RefPtr<StringImpl> text;
+ AtomicString tagName;
+ bool beginTag;
+ bool selfClosingTag;
+ bool brokenXMLStyle;
+ OwnPtr<Vector<UChar> > m_sourceInfo;
+};
+
+enum DoctypeState {
+ DoctypeBegin,
+ DoctypeBeforeName,
+ DoctypeName,
+ DoctypeAfterName,
+ DoctypeBeforePublicID,
+ DoctypePublicID,
+ DoctypeAfterPublicID,
+ DoctypeBeforeSystemID,
+ DoctypeSystemID,
+ DoctypeAfterSystemID,
+ DoctypeBogus
+};
+
+class DoctypeToken {
+public:
+ DoctypeToken() {}
+
+ void reset()
+ {
+ m_name.clear();
+ m_publicID.clear();
+ m_systemID.clear();
+ m_state = DoctypeBegin;
+ m_source.clear();
+ m_forceQuirks = false;
+ }
+
+ DoctypeState state() { return m_state; }
+ void setState(DoctypeState s) { m_state = s; }
+
+ Vector<UChar> m_name;
+ Vector<UChar> m_publicID;
+ Vector<UChar> m_systemID;
+ DoctypeState m_state;
+
+ Vector<UChar> m_source;
+
+ bool m_forceQuirks; // Used by the HTML5 parser.
+};
+
+//-----------------------------------------------------------------------------
/**
* The parser for HTML. It receives a stream of tokens from the LegacyHTMLDocumentParser, and
diff --git a/WebCore/html/LegacyPreloadScanner.cpp b/WebCore/html/LegacyPreloadScanner.cpp
deleted file mode 100644
index c9fda4f..0000000
--- a/WebCore/html/LegacyPreloadScanner.cpp
+++ /dev/null
@@ -1,856 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
- * Copyright (C) 2009 Torch Mobile, Inc. http://www.torchmobile.com/
- *
- * 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 "LegacyPreloadScanner.h"
-
-#include "AtomicString.h"
-#include "CachedCSSStyleSheet.h"
-#include "CachedImage.h"
-#include "CachedResource.h"
-#include "CachedResourceClient.h"
-#include "CachedScript.h"
-#include "CSSHelper.h"
-#include "DocLoader.h"
-#include "Document.h"
-#include "Frame.h"
-#include "FrameLoader.h"
-#include "HTMLLinkElement.h"
-#include "HTMLNames.h"
-#include <wtf/text/CString.h>
-#include <wtf/CurrentTime.h>
-#include <wtf/unicode/Unicode.h>
-
-// Use __GNUC__ instead of PLATFORM(GCC) to stay consistent with the gperf generated c file
-#ifdef __GNUC__
-// The main tokenizer includes this too so we are getting two copies of the data. However, this way the code gets inlined.
-#include "HTMLEntityNames.cpp"
-#else
-// Not inlined for non-GCC compilers
-struct Entity {
- const char* name;
- int code;
-};
-const struct Entity* findEntity(register const char* str, register unsigned int len);
-#endif
-
-#define PRELOAD_DEBUG 0
-
-using namespace WTF;
-
-namespace WebCore {
-
-using namespace HTMLNames;
-
-LegacyPreloadScanner::LegacyPreloadScanner(Document* doc)
- : m_inProgress(false)
- , m_timeUsed(0)
- , m_bodySeen(false)
- , m_document(doc)
-{
-#if PRELOAD_DEBUG
- printf("CREATING PRELOAD SCANNER FOR %s\n", m_document->url().string().latin1().data());
-#endif
-}
-
-LegacyPreloadScanner::~LegacyPreloadScanner()
-{
-#if PRELOAD_DEBUG
- printf("DELETING PRELOAD SCANNER FOR %s\n", m_document->url().string().latin1().data());
- printf("TOTAL TIME USED %.4fs\n", m_timeUsed);
-#endif
-}
-
-void LegacyPreloadScanner::begin()
-{
- ASSERT(!m_inProgress);
- reset();
- m_inProgress = true;
-}
-
-void LegacyPreloadScanner::end()
-{
- ASSERT(m_inProgress);
- m_inProgress = false;
-}
-
-void LegacyPreloadScanner::reset()
-{
- m_source.clear();
-
- m_state = Data;
- m_escape = false;
- m_contentModel = PCDATA;
- m_commentPos = 0;
-
- m_closeTag = false;
- m_tagName.clear();
- m_attributeName.clear();
- m_attributeValue.clear();
- m_lastStartTag = AtomicString();
-
- m_urlToLoad = String();
- m_charset = String();
- m_linkIsStyleSheet = false;
- m_lastCharacterIndex = 0;
- clearLastCharacters();
-
- m_cssState = CSSInitial;
- m_cssRule.clear();
- m_cssRuleValue.clear();
-}
-
-bool LegacyPreloadScanner::scanningBody() const
-{
- return m_document->body() || m_bodySeen;
-}
-
-void LegacyPreloadScanner::write(const SegmentedString& source)
-{
-#if PRELOAD_DEBUG
- double startTime = currentTime();
-#endif
- tokenize(source);
-#if PRELOAD_DEBUG
- m_timeUsed += currentTime() - startTime;
-#endif
-}
-
-static inline bool isWhitespace(UChar c)
-{
- return c == ' ' || c == '\n' || c == '\r' || c == '\t';
-}
-
-inline void LegacyPreloadScanner::clearLastCharacters()
-{
- memset(m_lastCharacters, 0, lastCharactersBufferSize * sizeof(UChar));
-}
-
-inline void LegacyPreloadScanner::rememberCharacter(UChar c)
-{
- m_lastCharacterIndex = (m_lastCharacterIndex + 1) % lastCharactersBufferSize;
- m_lastCharacters[m_lastCharacterIndex] = c;
-}
-
-inline bool LegacyPreloadScanner::lastCharactersMatch(const char* chars, unsigned count) const
-{
- unsigned pos = m_lastCharacterIndex;
- while (count) {
- if (chars[count - 1] != m_lastCharacters[pos])
- return false;
- --count;
- if (!pos)
- pos = lastCharactersBufferSize;
- --pos;
- }
- return true;
-}
-
-static inline unsigned legalEntityFor(unsigned value)
-{
- // FIXME There is a table for more exceptions in the HTML5 specification.
- if (value == 0 || value > 0x10FFFF || (value >= 0xD800 && value <= 0xDFFF))
- return 0xFFFD;
- return value;
-}
-
-unsigned LegacyPreloadScanner::consumeEntity(SegmentedString& source, bool& notEnoughCharacters)
-{
- enum EntityState {
- Initial,
- NumberType,
- MaybeHex,
- Hex,
- Decimal,
- Named
- };
- EntityState entityState = Initial;
- unsigned result = 0;
- Vector<UChar, 10> seenChars;
- Vector<char, 10> entityName;
-
- while (!source.isEmpty()) {
- UChar cc = *source;
- seenChars.append(cc);
- switch (entityState) {
- case Initial:
- if (isWhitespace(cc) || cc == '<' || cc == '&')
- return 0;
- else if (cc == '#')
- entityState = NumberType;
- else if ((cc >= 'a' && cc <= 'z') || (cc >= 'A' && cc <= 'Z')) {
- entityName.append(cc);
- entityState = Named;
- } else
- return 0;
- break;
- case NumberType:
- if (cc == 'x' || cc == 'X')
- entityState = MaybeHex;
- else if (cc >= '0' && cc <= '9') {
- entityState = Decimal;
- result = cc - '0';
- } else {
- source.push('#');
- return 0;
- }
- break;
- case MaybeHex:
- if (cc >= '0' && cc <= '9')
- result = cc - '0';
- else if (cc >= 'a' && cc <= 'f')
- result = 10 + cc - 'a';
- else if (cc >= 'A' && cc <= 'F')
- result = 10 + cc - 'A';
- else {
- source.push('#');
- source.push(seenChars[1]);
- return 0;
- }
- entityState = Hex;
- break;
- case Hex:
- if (cc >= '0' && cc <= '9')
- result = result * 16 + cc - '0';
- else if (cc >= 'a' && cc <= 'f')
- result = result * 16 + 10 + cc - 'a';
- else if (cc >= 'A' && cc <= 'F')
- result = result * 16 + 10 + cc - 'A';
- else if (cc == ';') {
- source.advance();
- return legalEntityFor(result);
- } else
- return legalEntityFor(result);
- break;
- case Decimal:
- if (cc >= '0' && cc <= '9')
- result = result * 10 + cc - '0';
- else if (cc == ';') {
- source.advance();
- return legalEntityFor(result);
- } else
- return legalEntityFor(result);
- break;
- case Named:
- // This is the attribute only version, generic version matches somewhat differently
- while (entityName.size() <= 8) {
- if (cc == ';') {
- const Entity* entity = findEntity(entityName.data(), entityName.size());
- if (entity) {
- source.advance();
- return entity->code;
- }
- break;
- }
- if (!(cc >= 'a' && cc <= 'z') && !(cc >= 'A' && cc <= 'Z') && !(cc >= '0' && cc <= '9')) {
- const Entity* entity = findEntity(entityName.data(), entityName.size());
- if (entity)
- return entity->code;
- break;
- }
- entityName.append(cc);
- source.advance();
- if (source.isEmpty())
- goto outOfCharacters;
- cc = *source;
- seenChars.append(cc);
- }
- if (seenChars.size() == 2)
- source.push(seenChars[0]);
- else if (seenChars.size() == 3) {
- source.push(seenChars[0]);
- source.push(seenChars[1]);
- } else
- source.prepend(SegmentedString(String(seenChars.data(), seenChars.size() - 1)));
- return 0;
- }
- source.advance();
- }
-outOfCharacters:
- notEnoughCharacters = true;
- source.prepend(SegmentedString(String(seenChars.data(), seenChars.size())));
- return 0;
-}
-
-void LegacyPreloadScanner::tokenize(const SegmentedString& source)
-{
- ASSERT(m_inProgress);
-
- m_source.append(source);
-
- // This is a simplified HTML5 Tokenizer
- // http://www.whatwg.org/specs/web-apps/current-work/#tokenisation0
- while (!m_source.isEmpty()) {
- UChar cc = *m_source;
- switch (m_state) {
- case Data:
- while (1) {
- rememberCharacter(cc);
- if (cc == '&') {
- if (m_contentModel == PCDATA || m_contentModel == RCDATA) {
- m_state = EntityData;
- break;
- }
- } else if (cc == '-') {
- if ((m_contentModel == RCDATA || m_contentModel == CDATA) && !m_escape) {
- if (lastCharactersMatch("<!--", 4))
- m_escape = true;
- }
- } else if (cc == '<') {
- if (m_contentModel == PCDATA || ((m_contentModel == RCDATA || m_contentModel == CDATA) && !m_escape)) {
- m_state = TagOpen;
- break;
- }
- } else if (cc == '>') {
- if ((m_contentModel == RCDATA || m_contentModel == CDATA) && m_escape) {
- if (lastCharactersMatch("-->", 3))
- m_escape = false;
- }
- }
- emitCharacter(cc);
- m_source.advance();
- if (m_source.isEmpty())
- return;
- cc = *m_source;
- }
- break;
- case EntityData:
- // should try to consume the entity but we only care about entities in attributes
- m_state = Data;
- break;
- case TagOpen:
- if (m_contentModel == RCDATA || m_contentModel == CDATA) {
- if (cc == '/')
- m_state = CloseTagOpen;
- else {
- m_state = Data;
- continue;
- }
- } else if (m_contentModel == PCDATA) {
- if (cc == '!')
- m_state = MarkupDeclarationOpen;
- else if (cc == '/')
- m_state = CloseTagOpen;
- else if (cc >= 'A' && cc <= 'Z') {
- m_tagName.clear();
- m_charset = String();
- m_tagName.append(cc + 0x20);
- m_closeTag = false;
- m_state = TagName;
- } else if (cc >= 'a' && cc <= 'z') {
- m_tagName.clear();
- m_charset = String();
- m_tagName.append(cc);
- m_closeTag = false;
- m_state = TagName;
- } else if (cc == '>') {
- m_state = Data;
- } else if (cc == '?') {
- m_state = BogusComment;
- } else {
- m_state = Data;
- continue;
- }
- }
- break;
- case CloseTagOpen:
- if (m_contentModel == RCDATA || m_contentModel == CDATA) {
- if (!m_lastStartTag.length()) {
- m_state = Data;
- continue;
- }
- if (m_source.length() < m_lastStartTag.length() + 1)
- return;
- Vector<UChar> tmpString;
- UChar tmpChar = 0;
- bool match = true;
- for (unsigned n = 0; n < m_lastStartTag.length() + 1; n++) {
- tmpChar = Unicode::toLower(*m_source);
- if (n < m_lastStartTag.length() && tmpChar != m_lastStartTag[n])
- match = false;
- tmpString.append(tmpChar);
- m_source.advance();
- }
- m_source.prepend(SegmentedString(String(tmpString.data(), tmpString.size())));
- if (!match || (!isWhitespace(tmpChar) && tmpChar != '>' && tmpChar != '/')) {
- m_state = Data;
- continue;
- }
- }
- if (cc >= 'A' && cc <= 'Z') {
- m_tagName.clear();
- m_charset = String();
- m_tagName.append(cc + 0x20);
- m_closeTag = true;
- m_state = TagName;
- } else if (cc >= 'a' && cc <= 'z') {
- m_tagName.clear();
- m_charset = String();
- m_tagName.append(cc);
- m_closeTag = true;
- m_state = TagName;
- } else if (cc == '>') {
- m_state = Data;
- } else
- m_state = BogusComment;
- break;
- case TagName:
- while (1) {
- if (isWhitespace(cc)) {
- m_state = BeforeAttributeName;
- break;
- }
- if (cc == '>') {
- emitTag();
- m_state = Data;
- break;
- }
- if (cc == '/') {
- m_state = BeforeAttributeName;
- break;
- }
- if (cc >= 'A' && cc <= 'Z')
- m_tagName.append(cc + 0x20);
- else
- m_tagName.append(cc);
- m_source.advance();
- if (m_source.isEmpty())
- return;
- cc = *m_source;
- }
- break;
- case BeforeAttributeName:
- if (isWhitespace(cc))
- ;
- else if (cc == '>') {
- emitTag();
- m_state = Data;
- } else if (cc >= 'A' && cc <= 'Z') {
- m_attributeName.clear();
- m_attributeValue.clear();
- m_attributeName.append(cc + 0x20);
- m_state = AttributeName;
- } else if (cc == '/')
- ;
- else {
- m_attributeName.clear();
- m_attributeValue.clear();
- m_attributeName.append(cc);
- m_state = AttributeName;
- }
- break;
- case AttributeName:
- while (1) {
- if (isWhitespace(cc)) {
- m_state = AfterAttributeName;
- break;
- }
- if (cc == '=') {
- m_state = BeforeAttributeValue;
- break;
- }
- if (cc == '>') {
- emitTag();
- m_state = Data;
- break;
- }
- if (cc == '/') {
- m_state = BeforeAttributeName;
- break;
- }
- if (cc >= 'A' && cc <= 'Z')
- m_attributeName.append(cc + 0x20);
- else
- m_attributeName.append(cc);
- m_source.advance();
- if (m_source.isEmpty())
- return;
- cc = *m_source;
- }
- break;
- case AfterAttributeName:
- if (isWhitespace(cc))
- ;
- else if (cc == '=')
- m_state = BeforeAttributeValue;
- else if (cc == '>') {
- emitTag();
- m_state = Data;
- } else if (cc >= 'A' && cc <= 'Z') {
- m_attributeName.clear();
- m_attributeValue.clear();
- m_attributeName.append(cc + 0x20);
- m_state = AttributeName;
- } else if (cc == '/')
- m_state = BeforeAttributeName;
- else {
- m_attributeName.clear();
- m_attributeValue.clear();
- m_attributeName.append(cc);
- m_state = AttributeName;
- }
- break;
- case BeforeAttributeValue:
- if (isWhitespace(cc))
- ;
- else if (cc == '"')
- m_state = AttributeValueDoubleQuoted;
- else if (cc == '&') {
- m_state = AttributeValueUnquoted;
- continue;
- } else if (cc == '\'')
- m_state = AttributeValueSingleQuoted;
- else if (cc == '>') {
- emitTag();
- m_state = Data;
- } else {
- m_attributeValue.append(cc);
- m_state = AttributeValueUnquoted;
- }
- break;
- case AttributeValueDoubleQuoted:
- while (1) {
- if (cc == '"') {
- processAttribute();
- m_state = BeforeAttributeName;
- break;
- }
- if (cc == '&') {
- m_stateBeforeEntityInAttributeValue = m_state;
- m_state = EntityInAttributeValue;
- break;
- }
- m_attributeValue.append(cc);
- m_source.advance();
- if (m_source.isEmpty())
- return;
- cc = *m_source;
- }
- break;
- case AttributeValueSingleQuoted:
- while (1) {
- if (cc == '\'') {
- processAttribute();
- m_state = BeforeAttributeName;
- break;
- }
- if (cc == '&') {
- m_stateBeforeEntityInAttributeValue = m_state;
- m_state = EntityInAttributeValue;
- break;
- }
- m_attributeValue.append(cc);
- m_source.advance();
- if (m_source.isEmpty())
- return;
- cc = *m_source;
- }
- break;
- case AttributeValueUnquoted:
- while (1) {
- if (isWhitespace(cc)) {
- processAttribute();
- m_state = BeforeAttributeName;
- break;
- }
- if (cc == '&') {
- m_stateBeforeEntityInAttributeValue = m_state;
- m_state = EntityInAttributeValue;
- break;
- }
- if (cc == '>') {
- processAttribute();
- emitTag();
- m_state = Data;
- break;
- }
- m_attributeValue.append(cc);
- m_source.advance();
- if (m_source.isEmpty())
- return;
- cc = *m_source;
- }
- break;
- case EntityInAttributeValue:
- {
- bool notEnoughCharacters = false;
- unsigned entity = consumeEntity(m_source, notEnoughCharacters);
- if (notEnoughCharacters)
- return;
- if (entity > 0xFFFF) {
- m_attributeValue.append(U16_LEAD(entity));
- m_attributeValue.append(U16_TRAIL(entity));
- } else if (entity)
- m_attributeValue.append(entity);
- else
- m_attributeValue.append('&');
- }
- m_state = m_stateBeforeEntityInAttributeValue;
- continue;
- case BogusComment:
- while (1) {
- if (cc == '>') {
- m_state = Data;
- break;
- }
- m_source.advance();
- if (m_source.isEmpty())
- return;
- cc = *m_source;
- }
- break;
- case MarkupDeclarationOpen: {
- if (cc == '-') {
- if (m_source.length() < 2)
- return;
- m_source.advance();
- cc = *m_source;
- if (cc == '-')
- m_state = CommentStart;
- else {
- m_state = BogusComment;
- continue;
- }
- // If we cared about the DOCTYPE we would test to enter those states here
- } else {
- m_state = BogusComment;
- continue;
- }
- break;
- }
- case CommentStart:
- if (cc == '-')
- m_state = CommentStartDash;
- else if (cc == '>')
- m_state = Data;
- else
- m_state = Comment;
- break;
- case CommentStartDash:
- if (cc == '-')
- m_state = CommentEnd;
- else if (cc == '>')
- m_state = Data;
- else
- m_state = Comment;
- break;
- case Comment:
- while (1) {
- if (cc == '-') {
- m_state = CommentEndDash;
- break;
- }
- m_source.advance();
- if (m_source.isEmpty())
- return;
- cc = *m_source;
- }
- break;
- case CommentEndDash:
- if (cc == '-')
- m_state = CommentEnd;
- else
- m_state = Comment;
- break;
- case CommentEnd:
- if (cc == '>')
- m_state = Data;
- else if (cc == '-')
- ;
- else
- m_state = Comment;
- break;
- }
- m_source.advance();
- }
-}
-
-void LegacyPreloadScanner::processAttribute()
-{
- AtomicString tag = AtomicString(m_tagName.data(), m_tagName.size());
- AtomicString attribute = AtomicString(m_attributeName.data(), m_attributeName.size());
-
- String value(m_attributeValue.data(), m_attributeValue.size());
- if (tag == scriptTag || tag == imgTag) {
- if (attribute == srcAttr && m_urlToLoad.isEmpty())
- m_urlToLoad = deprecatedParseURL(value);
- else if (attribute == charsetAttr)
- m_charset = value;
- } else if (tag == linkTag) {
- if (attribute == hrefAttr && m_urlToLoad.isEmpty())
- m_urlToLoad = deprecatedParseURL(value);
- else if (attribute == relAttr) {
- HTMLLinkElement::RelAttribute rel;
- HTMLLinkElement::tokenizeRelAttribute(value, rel);
- m_linkIsStyleSheet = rel.m_isStyleSheet && !rel.m_isAlternate && !rel.m_isIcon && !rel.m_isDNSPrefetch;
- } else if (attribute == charsetAttr)
- m_charset = value;
- }
-}
-
-inline void LegacyPreloadScanner::emitCharacter(UChar c)
-{
- if (m_contentModel == CDATA && m_lastStartTag == styleTag)
- tokenizeCSS(c);
-}
-
-inline void LegacyPreloadScanner::tokenizeCSS(UChar c)
-{
- // We are just interested in @import rules, no need for real tokenization here
- // Searching for other types of resources is probably low payoff
- switch (m_cssState) {
- case CSSInitial:
- if (c == '@')
- m_cssState = CSSRuleStart;
- else if (c == '/')
- m_cssState = CSSMaybeComment;
- break;
- case CSSMaybeComment:
- if (c == '*')
- m_cssState = CSSComment;
- else
- m_cssState = CSSInitial;
- break;
- case CSSComment:
- if (c == '*')
- m_cssState = CSSMaybeCommentEnd;
- break;
- case CSSMaybeCommentEnd:
- if (c == '/')
- m_cssState = CSSInitial;
- else if (c == '*')
- ;
- else
- m_cssState = CSSComment;
- break;
- case CSSRuleStart:
- if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
- m_cssRule.clear();
- m_cssRuleValue.clear();
- m_cssRule.append(c);
- m_cssState = CSSRule;
- } else
- m_cssState = CSSInitial;
- break;
- case CSSRule:
- if (isWhitespace(c))
- m_cssState = CSSAfterRule;
- else if (c == ';')
- m_cssState = CSSInitial;
- else
- m_cssRule.append(c);
- break;
- case CSSAfterRule:
- if (isWhitespace(c))
- ;
- else if (c == ';')
- m_cssState = CSSInitial;
- else {
- m_cssState = CSSRuleValue;
- m_cssRuleValue.append(c);
- }
- break;
- case CSSRuleValue:
- if (isWhitespace(c))
- m_cssState = CSSAfterRuleValue;
- else if (c == ';') {
- emitCSSRule();
- m_cssState = CSSInitial;
- } else
- m_cssRuleValue.append(c);
- break;
- case CSSAfterRuleValue:
- if (isWhitespace(c))
- ;
- else if (c == ';') {
- emitCSSRule();
- m_cssState = CSSInitial;
- } else {
- // FIXME media rules
- m_cssState = CSSInitial;
- }
- break;
- }
-}
-
-void LegacyPreloadScanner::emitTag()
-{
- if (m_closeTag) {
- m_contentModel = PCDATA;
- m_cssState = CSSInitial;
- clearLastCharacters();
- return;
- }
-
- AtomicString tag(m_tagName.data(), m_tagName.size());
- m_lastStartTag = tag;
-
- if (tag == textareaTag || tag == titleTag)
- m_contentModel = RCDATA;
- else if (tag == styleTag || tag == xmpTag || tag == scriptTag || tag == iframeTag || tag == noembedTag || tag == noframesTag)
- m_contentModel = CDATA;
- else if (tag == noscriptTag)
- // we wouldn't be here if scripts were disabled
- m_contentModel = CDATA;
- else if (tag == plaintextTag)
- m_contentModel = PLAINTEXT;
- else
- m_contentModel = PCDATA;
-
- if (tag == bodyTag)
- m_bodySeen = true;
-
- if (m_urlToLoad.isEmpty()) {
- m_linkIsStyleSheet = false;
- return;
- }
-
- if (tag == scriptTag)
- m_document->docLoader()->preload(CachedResource::Script, m_urlToLoad, m_charset, scanningBody());
- else if (tag == imgTag)
- m_document->docLoader()->preload(CachedResource::ImageResource, m_urlToLoad, String(), scanningBody());
- else if (tag == linkTag && m_linkIsStyleSheet)
- m_document->docLoader()->preload(CachedResource::CSSStyleSheet, m_urlToLoad, m_charset, scanningBody());
-
- m_urlToLoad = String();
- m_charset = String();
- m_linkIsStyleSheet = false;
-}
-
-void LegacyPreloadScanner::emitCSSRule()
-{
- String rule(m_cssRule.data(), m_cssRule.size());
- if (equalIgnoringCase(rule, "import") && !m_cssRuleValue.isEmpty()) {
- String value(m_cssRuleValue.data(), m_cssRuleValue.size());
- String url = deprecatedParseURL(value);
- if (!url.isEmpty())
- m_document->docLoader()->preload(CachedResource::CSSStyleSheet, url, String(), scanningBody());
- }
- m_cssRule.clear();
- m_cssRuleValue.clear();
-}
-
-}
diff --git a/WebCore/html/LegacyPreloadScanner.h b/WebCore/html/LegacyPreloadScanner.h
deleted file mode 100644
index 95710ab..0000000
--- a/WebCore/html/LegacyPreloadScanner.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef LegacyPreloadScanner_h
-#define LegacyPreloadScanner_h
-
-#include "AtomicString.h"
-#include "SegmentedString.h"
-#include <wtf/Noncopyable.h>
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
- class CachedResource;
- class CachedResourceClient;
- class Document;
-
- class LegacyPreloadScanner : public Noncopyable {
- public:
- LegacyPreloadScanner(Document*);
- ~LegacyPreloadScanner();
- void begin();
- void write(const SegmentedString&);
- void end();
- bool inProgress() const { return m_inProgress; }
-
- bool scanningBody() const;
-
- static unsigned consumeEntity(SegmentedString&, bool& notEnoughCharacters);
-
- private:
- void tokenize(const SegmentedString&);
- void reset();
-
- void emitTag();
- void emitCharacter(UChar);
-
- void tokenizeCSS(UChar);
- void emitCSSRule();
-
- void processAttribute();
-
-
- void clearLastCharacters();
- void rememberCharacter(UChar);
- bool lastCharactersMatch(const char*, unsigned count) const;
-
- bool m_inProgress;
- SegmentedString m_source;
-
- enum State {
- Data,
- EntityData,
- TagOpen,
- CloseTagOpen,
- TagName,
- BeforeAttributeName,
- AttributeName,
- AfterAttributeName,
- BeforeAttributeValue,
- AttributeValueDoubleQuoted,
- AttributeValueSingleQuoted,
- AttributeValueUnquoted,
- EntityInAttributeValue,
- BogusComment,
- MarkupDeclarationOpen,
- CommentStart,
- CommentStartDash,
- Comment,
- CommentEndDash,
- CommentEnd
- };
- State m_state;
- bool m_escape;
- enum ContentModel {
- PCDATA,
- RCDATA,
- CDATA,
- PLAINTEXT
- };
- ContentModel m_contentModel;
- unsigned m_commentPos;
- State m_stateBeforeEntityInAttributeValue;
-
- static const unsigned lastCharactersBufferSize = 8;
- UChar m_lastCharacters[lastCharactersBufferSize];
- unsigned m_lastCharacterIndex;
-
- bool m_closeTag;
- Vector<UChar, 32> m_tagName;
- Vector<UChar, 32> m_attributeName;
- Vector<UChar> m_attributeValue;
- AtomicString m_lastStartTag;
-
- String m_urlToLoad;
- String m_charset;
- bool m_linkIsStyleSheet;
-
- enum CSSState {
- CSSInitial,
- CSSMaybeComment,
- CSSComment,
- CSSMaybeCommentEnd,
- CSSRuleStart,
- CSSRule,
- CSSAfterRule,
- CSSRuleValue,
- CSSAfterRuleValue
- };
- CSSState m_cssState;
- Vector<UChar, 16> m_cssRule;
- Vector<UChar> m_cssRuleValue;
-
- double m_timeUsed;
-
- bool m_bodySeen;
- Document* m_document;
- };
-
-}
-
-#endif
diff --git a/WebCore/html/ThreadableBlobRegistry.cpp b/WebCore/html/ThreadableBlobRegistry.cpp
new file mode 100644
index 0000000..1df290d
--- /dev/null
+++ b/WebCore/html/ThreadableBlobRegistry.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 "ThreadableBlobRegistry.h"
+
+#include "BlobData.h"
+#include "BlobRegistry.h"
+#include "CrossThreadTask.h"
+#include "NotImplemented.h"
+#include "ScriptExecutionContext.h"
+#include "WorkerContext.h"
+#include "WorkerLoaderProxy.h"
+#include "WorkerThread.h"
+
+namespace WebCore {
+
+static void postTaskToMainThread(ScriptExecutionContext* scriptExecutionContext, PassOwnPtr<ScriptExecutionContext::Task> task)
+{
+#if ENABLE(WORKERS)
+ ASSERT(scriptExecutionContext->isWorkerContext());
+ WorkerLoaderProxy& proxy = static_cast<WorkerContext*>(scriptExecutionContext)->thread()->workerLoaderProxy();
+ proxy.postTaskToLoader(task);
+#else
+ notImplemented();
+#endif
+}
+
+static void registerBlobURLTask(ScriptExecutionContext*, const KURL& url, PassOwnPtr<BlobData> blobData)
+{
+ BlobRegistry::instance().registerBlobURL(url, blobData);
+}
+
+void ThreadableBlobRegistry::registerBlobURL(ScriptExecutionContext* scriptExecutionContext, const KURL& url, PassOwnPtr<BlobData> blobData)
+{
+ if (scriptExecutionContext->isWorkerContext())
+ postTaskToMainThread(scriptExecutionContext, createCallbackTask(&registerBlobURLTask, url, blobData));
+ else
+ registerBlobURLTask(scriptExecutionContext, url, blobData);
+}
+
+static void registerBlobURLFromTask(ScriptExecutionContext*, const KURL& url, const KURL& srcURL)
+{
+ BlobRegistry::instance().registerBlobURL(url, srcURL);
+}
+
+void ThreadableBlobRegistry::registerBlobURL(ScriptExecutionContext* scriptExecutionContext, const KURL& url, const KURL& srcURL)
+{
+ if (scriptExecutionContext->isWorkerContext())
+ postTaskToMainThread(scriptExecutionContext, createCallbackTask(&registerBlobURLFromTask, url, srcURL));
+ else
+ registerBlobURLFromTask(scriptExecutionContext, url, srcURL);
+}
+
+static void unregisterBlobURLTask(ScriptExecutionContext*, const KURL& url)
+{
+ BlobRegistry::instance().unregisterBlobURL(url);
+}
+
+void ThreadableBlobRegistry::unregisterBlobURL(ScriptExecutionContext* scriptExecutionContext, const KURL& url)
+{
+ if (scriptExecutionContext->isWorkerContext())
+ postTaskToMainThread(scriptExecutionContext, createCallbackTask(&unregisterBlobURLTask, url));
+ else
+ unregisterBlobURLTask(scriptExecutionContext, url);
+}
+
+} // namespace WebCore
diff --git a/WebCore/html/ThreadableBlobRegistry.h b/WebCore/html/ThreadableBlobRegistry.h
new file mode 100644
index 0000000..7dce6bb
--- /dev/null
+++ b/WebCore/html/ThreadableBlobRegistry.h
@@ -0,0 +1,51 @@
+/*
+ * 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 ThreadableBlobRegistry_h
+#define ThreadableBlobRegistry_h
+
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class BlobData;
+class KURL;
+class ScriptExecutionContext;
+
+class ThreadableBlobRegistry {
+public:
+ static void registerBlobURL(ScriptExecutionContext*, const KURL&, PassOwnPtr<BlobData>);
+ static void registerBlobURL(ScriptExecutionContext*, const KURL&, const KURL& srcURL);
+ static void unregisterBlobURL(ScriptExecutionContext*, const KURL&);
+};
+
+} // namespace WebCore
+
+#endif // ThreadableBlobRegistry_h
diff --git a/WebCore/html/canvas/CanvasNumberArray.idl b/WebCore/html/canvas/CanvasNumberArray.idl
deleted file mode 100644
index 036d4ee..0000000
--- a/WebCore/html/canvas/CanvasNumberArray.idl
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 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,
- * 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.
- */
-
-module html {
- interface [
- Conditional=3D_CANVAS,
- HasCustomIndexGetter
- ] CanvasNumberArray {
- readonly attribute unsigned long length;
- };
-}
diff --git a/WebCore/html/canvas/CanvasPattern.cpp b/WebCore/html/canvas/CanvasPattern.cpp
index 62a4620..818d7d3 100644
--- a/WebCore/html/canvas/CanvasPattern.cpp
+++ b/WebCore/html/canvas/CanvasPattern.cpp
@@ -57,7 +57,7 @@ void CanvasPattern::parseRepetitionType(const String& type, bool& repeatX, bool&
ec = SYNTAX_ERR;
}
-CanvasPattern::CanvasPattern(Image* image, bool repeatX, bool repeatY, bool originClean)
+CanvasPattern::CanvasPattern(PassRefPtr<Image> image, bool repeatX, bool repeatY, bool originClean)
: m_pattern(Pattern::create(image, repeatX, repeatY))
, m_originClean(originClean)
{
diff --git a/WebCore/html/canvas/CanvasPattern.h b/WebCore/html/canvas/CanvasPattern.h
index 91e0794..58848a9 100644
--- a/WebCore/html/canvas/CanvasPattern.h
+++ b/WebCore/html/canvas/CanvasPattern.h
@@ -41,7 +41,7 @@ namespace WebCore {
public:
static void parseRepetitionType(const String&, bool& repeatX, bool& repeatY, ExceptionCode&);
- static PassRefPtr<CanvasPattern> create(Image* image, bool repeatX, bool repeatY, bool originClean)
+ static PassRefPtr<CanvasPattern> create(PassRefPtr<Image> image, bool repeatX, bool repeatY, bool originClean)
{
return adoptRef(new CanvasPattern(image, repeatX, repeatY, originClean));
}
@@ -51,7 +51,7 @@ namespace WebCore {
bool originClean() const { return m_originClean; }
private:
- CanvasPattern(Image*, bool repeatX, bool repeatY, bool originClean);
+ CanvasPattern(PassRefPtr<Image>, bool repeatX, bool repeatY, bool originClean);
RefPtr<Pattern> m_pattern;
bool m_originClean;
diff --git a/WebCore/html/canvas/CanvasRenderingContext2D.cpp b/WebCore/html/canvas/CanvasRenderingContext2D.cpp
index 559ddda..58ec1d0 100644
--- a/WebCore/html/canvas/CanvasRenderingContext2D.cpp
+++ b/WebCore/html/canvas/CanvasRenderingContext2D.cpp
@@ -126,7 +126,7 @@ CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, bo
return;
if (FrameView* view = canvas->document()->view()) {
if (ScrollView* rootView = view->root()) {
- if (HostWindow* hostWindow = view->root()->hostWindow()) {
+ if (HostWindow* hostWindow = rootView->hostWindow()) {
// Set up our context
GraphicsContext3D::Attributes attr;
attr.stencil = true;
@@ -167,8 +167,8 @@ void CanvasRenderingContext2D::reset()
}
CanvasRenderingContext2D::State::State()
- : m_strokeStyle(CanvasStyle::create(Color::black))
- , m_fillStyle(CanvasStyle::create(Color::black))
+ : m_strokeStyle(CanvasStyle::createFromRGBA(Color::black))
+ , m_fillStyle(CanvasStyle::createFromRGBA(Color::black))
, m_lineWidth(1)
, m_lineCap(ButtCap)
, m_lineJoin(MiterJoin)
@@ -550,82 +550,82 @@ void CanvasRenderingContext2D::setStrokeColor(const String& color)
{
if (color == state().m_unparsedStrokeColor)
return;
- setStrokeStyle(CanvasStyle::create(color));
+ setStrokeStyle(CanvasStyle::createFromString(color));
state().m_unparsedStrokeColor = color;
}
void CanvasRenderingContext2D::setStrokeColor(float grayLevel)
{
- if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentColor(grayLevel, grayLevel, grayLevel, 1.0f))
+ if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, 1.0f))
return;
- setStrokeStyle(CanvasStyle::create(grayLevel, 1));
+ setStrokeStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, 1.0f));
}
void CanvasRenderingContext2D::setStrokeColor(const String& color, float alpha)
{
- setStrokeStyle(CanvasStyle::create(color, alpha));
+ setStrokeStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha));
}
void CanvasRenderingContext2D::setStrokeColor(float grayLevel, float alpha)
{
- if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentColor(grayLevel, grayLevel, grayLevel, alpha))
+ if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, alpha))
return;
- setStrokeStyle(CanvasStyle::create(grayLevel, alpha));
+ setStrokeStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, alpha));
}
void CanvasRenderingContext2D::setStrokeColor(float r, float g, float b, float a)
{
- if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentColor(r, g, b, a))
+ if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentRGBA(r, g, b, a))
return;
- setStrokeStyle(CanvasStyle::create(r, g, b, a));
+ setStrokeStyle(CanvasStyle::createFromRGBAChannels(r, g, b, a));
}
void CanvasRenderingContext2D::setStrokeColor(float c, float m, float y, float k, float a)
{
- if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentColor(c, m, y, k, a))
+ if (state().m_strokeStyle && state().m_strokeStyle->isEquivalentCMYKA(c, m, y, k, a))
return;
- setStrokeStyle(CanvasStyle::create(c, m, y, k, a));
+ setStrokeStyle(CanvasStyle::createFromCMYKAChannels(c, m, y, k, a));
}
void CanvasRenderingContext2D::setFillColor(const String& color)
{
if (color == state().m_unparsedFillColor)
return;
- setFillStyle(CanvasStyle::create(color));
+ setFillStyle(CanvasStyle::createFromString(color));
state().m_unparsedFillColor = color;
}
void CanvasRenderingContext2D::setFillColor(float grayLevel)
{
- if (state().m_fillStyle && state().m_fillStyle->isEquivalentColor(grayLevel, grayLevel, grayLevel, 1.0f))
+ if (state().m_fillStyle && state().m_fillStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, 1.0f))
return;
- setFillStyle(CanvasStyle::create(grayLevel, 1));
+ setFillStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, 1.0f));
}
void CanvasRenderingContext2D::setFillColor(const String& color, float alpha)
{
- setFillStyle(CanvasStyle::create(color, alpha));
+ setFillStyle(CanvasStyle::createFromStringWithOverrideAlpha(color, alpha));
}
void CanvasRenderingContext2D::setFillColor(float grayLevel, float alpha)
{
- if (state().m_fillStyle && state().m_fillStyle->isEquivalentColor(grayLevel, grayLevel, grayLevel, alpha))
+ if (state().m_fillStyle && state().m_fillStyle->isEquivalentRGBA(grayLevel, grayLevel, grayLevel, alpha))
return;
- setFillStyle(CanvasStyle::create(grayLevel, alpha));
+ setFillStyle(CanvasStyle::createFromGrayLevelWithAlpha(grayLevel, alpha));
}
void CanvasRenderingContext2D::setFillColor(float r, float g, float b, float a)
{
- if (state().m_fillStyle && state().m_fillStyle->isEquivalentColor(r, g, b, a))
+ if (state().m_fillStyle && state().m_fillStyle->isEquivalentRGBA(r, g, b, a))
return;
- setFillStyle(CanvasStyle::create(r, g, b, a));
+ setFillStyle(CanvasStyle::createFromRGBAChannels(r, g, b, a));
}
void CanvasRenderingContext2D::setFillColor(float c, float m, float y, float k, float a)
{
- if (state().m_fillStyle && state().m_fillStyle->isEquivalentColor(c, m, y, k, a))
+ if (state().m_fillStyle && state().m_fillStyle->isEquivalentCMYKA(c, m, y, k, a))
return;
- setFillStyle(CanvasStyle::create(c, m, y, k, a));
+ setFillStyle(CanvasStyle::createFromCMYKAChannels(c, m, y, k, a));
}
void CanvasRenderingContext2D::beginPath()
@@ -825,8 +825,16 @@ void CanvasRenderingContext2D::stroke()
c->beginPath();
c->addPath(m_path);
+#if PLATFORM(QT)
+ // Fast approximation of the stroke's bounding rect.
+ // This yields a slightly oversized rect but is very fast
+ // compared to Path::strokeBoundingRect().
+ FloatRect boundingRect = m_path.platformPath().controlPointRect();
+ boundingRect.inflate(state().m_miterLimit + state().m_lineWidth);
+#else
CanvasStrokeStyleApplier strokeApplier(this);
FloatRect boundingRect = m_path.strokeBoundingRect(&strokeApplier);
+#endif
willDraw(boundingRect);
c->strokePath();
@@ -1264,7 +1272,7 @@ void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, const
sourceCanvas->makeRenderingResultsAvailable();
- c->drawImage(buffer->image(), DeviceColorSpace, destRect, sourceRect, state().m_globalComposite);
+ c->drawImageBuffer(buffer, DeviceColorSpace, destRect, sourceRect, state().m_globalComposite);
willDraw(destRect); // This call comes after drawImage, since the buffer we draw into may be our own, and we need to make sure it is dirty.
// FIXME: Arguably willDraw should become didDraw and occur after drawing calls and not before them to avoid problems like this.
}
@@ -1464,7 +1472,7 @@ PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLCanvasElem
CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec);
if (ec)
return 0;
- return CanvasPattern::create(canvas->buffer()->image(), repeatX, repeatY, canvas->originClean());
+ return CanvasPattern::create(canvas->copiedImage(), repeatX, repeatY, canvas->originClean());
}
void CanvasRenderingContext2D::willDraw(const FloatRect& r, unsigned options)
@@ -1820,7 +1828,7 @@ void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, flo
maskImageContext->drawBidiText(font, textRun, location);
c->save();
- c->clipToImageBuffer(maskRect, maskImage.get());
+ c->clipToImageBuffer(maskImage.get(), maskRect);
drawStyle->applyFillColor(c);
c->fillRect(maskRect);
c->restore();
diff --git a/WebCore/html/canvas/CanvasStyle.cpp b/WebCore/html/canvas/CanvasStyle.cpp
index 52b31c8..fd3c6e5 100644
--- a/WebCore/html/canvas/CanvasStyle.cpp
+++ b/WebCore/html/canvas/CanvasStyle.cpp
@@ -55,12 +55,6 @@ CanvasStyle::CanvasStyle(RGBA32 rgba)
{
}
-CanvasStyle::CanvasStyle(float grayLevel)
- : m_type(RGBA)
- , m_rgba(makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, 1.0f))
-{
-}
-
CanvasStyle::CanvasStyle(float grayLevel, float alpha)
: m_type(RGBA)
, m_rgba(makeRGBA32FromFloats(grayLevel, grayLevel, grayLevel, alpha))
@@ -92,7 +86,7 @@ CanvasStyle::CanvasStyle(PassRefPtr<CanvasPattern> pattern)
{
}
-PassRefPtr<CanvasStyle> CanvasStyle::create(const String& color)
+PassRefPtr<CanvasStyle> CanvasStyle::createFromString(const String& color)
{
RGBA32 rgba;
if (!CSSParser::parseColor(rgba, color))
@@ -100,7 +94,7 @@ PassRefPtr<CanvasStyle> CanvasStyle::create(const String& color)
return adoptRef(new CanvasStyle(rgba));
}
-PassRefPtr<CanvasStyle> CanvasStyle::create(const String& color, float alpha)
+PassRefPtr<CanvasStyle> CanvasStyle::createFromStringWithOverrideAlpha(const String& color, float alpha)
{
RGBA32 rgba;
if (!CSSParser::parseColor(rgba, color))
@@ -108,13 +102,13 @@ PassRefPtr<CanvasStyle> CanvasStyle::create(const String& color, float alpha)
return adoptRef(new CanvasStyle(colorWithOverrideAlpha(rgba, alpha)));
}
-PassRefPtr<CanvasStyle> CanvasStyle::create(PassRefPtr<CanvasGradient> gradient)
+PassRefPtr<CanvasStyle> CanvasStyle::createFromGradient(PassRefPtr<CanvasGradient> gradient)
{
if (!gradient)
return 0;
return adoptRef(new CanvasStyle(gradient));
}
-PassRefPtr<CanvasStyle> CanvasStyle::create(PassRefPtr<CanvasPattern> pattern)
+PassRefPtr<CanvasStyle> CanvasStyle::createFromPattern(PassRefPtr<CanvasPattern> pattern)
{
if (!pattern)
return 0;
@@ -144,7 +138,7 @@ bool CanvasStyle::isEquivalentColor(const CanvasStyle& other) const
return false;
}
-bool CanvasStyle::isEquivalentColor(float r, float g, float b, float a) const
+bool CanvasStyle::isEquivalentRGBA(float r, float g, float b, float a) const
{
if (m_type != RGBA)
return false;
@@ -152,7 +146,7 @@ bool CanvasStyle::isEquivalentColor(float r, float g, float b, float a) const
return m_rgba == makeRGBA32FromFloats(r, g, b, a);
}
-bool CanvasStyle::isEquivalentColor(float c, float m, float y, float k, float a) const
+bool CanvasStyle::isEquivalentCMYKA(float c, float m, float y, float k, float a) const
{
if (m_type != CMYKA)
return false;
diff --git a/WebCore/html/canvas/CanvasStyle.h b/WebCore/html/canvas/CanvasStyle.h
index 8e47e63..3ca760a 100644
--- a/WebCore/html/canvas/CanvasStyle.h
+++ b/WebCore/html/canvas/CanvasStyle.h
@@ -38,15 +38,14 @@ namespace WebCore {
class CanvasStyle : public RefCounted<CanvasStyle> {
public:
- static PassRefPtr<CanvasStyle> create(RGBA32 rgba) { return adoptRef(new CanvasStyle(rgba)); }
- static PassRefPtr<CanvasStyle> create(const String& color);
- static PassRefPtr<CanvasStyle> create(const String& color, float alpha);
- static PassRefPtr<CanvasStyle> create(float grayLevel) { return adoptRef(new CanvasStyle(grayLevel)); }
- static PassRefPtr<CanvasStyle> create(float grayLevel, float alpha) { return adoptRef(new CanvasStyle(grayLevel, alpha)); }
- static PassRefPtr<CanvasStyle> create(float r, float g, float b, float a) { return adoptRef(new CanvasStyle(r, g, b, a)); }
- static PassRefPtr<CanvasStyle> create(float c, float m, float y, float k, float a) { return adoptRef(new CanvasStyle(c, m, y, k, a)); }
- static PassRefPtr<CanvasStyle> create(PassRefPtr<CanvasGradient> gradient);
- static PassRefPtr<CanvasStyle> create(PassRefPtr<CanvasPattern> pattern);
+ static PassRefPtr<CanvasStyle> createFromRGBA(RGBA32 rgba) { return adoptRef(new CanvasStyle(rgba)); }
+ static PassRefPtr<CanvasStyle> createFromString(const String& color);
+ static PassRefPtr<CanvasStyle> createFromStringWithOverrideAlpha(const String& color, float alpha);
+ static PassRefPtr<CanvasStyle> createFromGrayLevelWithAlpha(float grayLevel, float alpha) { return adoptRef(new CanvasStyle(grayLevel, alpha)); }
+ static PassRefPtr<CanvasStyle> createFromRGBAChannels(float r, float g, float b, float a) { return adoptRef(new CanvasStyle(r, g, b, a)); }
+ static PassRefPtr<CanvasStyle> createFromCMYKAChannels(float c, float m, float y, float k, float a) { return adoptRef(new CanvasStyle(c, m, y, k, a)); }
+ static PassRefPtr<CanvasStyle> createFromGradient(PassRefPtr<CanvasGradient>);
+ static PassRefPtr<CanvasStyle> createFromPattern(PassRefPtr<CanvasPattern>);
String color() const { return Color(m_rgba).serialized(); }
CanvasGradient* canvasGradient() const { return m_gradient.get(); }
@@ -56,12 +55,11 @@ namespace WebCore {
void applyStrokeColor(GraphicsContext*);
bool isEquivalentColor(const CanvasStyle&) const;
- bool isEquivalentColor(float r, float g, float b, float a) const;
- bool isEquivalentColor(float c, float m, float y, float k, float a) const;
+ bool isEquivalentRGBA(float r, float g, float b, float a) const;
+ bool isEquivalentCMYKA(float c, float m, float y, float k, float a) const;
private:
CanvasStyle(RGBA32 rgba);
- CanvasStyle(float grayLevel);
CanvasStyle(float grayLevel, float alpha);
CanvasStyle(float r, float g, float b, float a);
CanvasStyle(float c, float m, float y, float k, float a);
diff --git a/WebCore/html/canvas/WebGLObject.cpp b/WebCore/html/canvas/WebGLObject.cpp
index 6a34269..5fd5534 100644
--- a/WebCore/html/canvas/WebGLObject.cpp
+++ b/WebCore/html/canvas/WebGLObject.cpp
@@ -35,8 +35,9 @@ namespace WebCore {
WebGLObject::WebGLObject(WebGLRenderingContext* context)
: m_object(0)
- , m_shouldDeleteObject(true)
, m_context(context)
+ , m_attachmentCount(0)
+ , m_deleted(false)
{
}
@@ -46,27 +47,26 @@ WebGLObject::~WebGLObject()
m_context->removeObject(this);
}
-void WebGLObject::setObject(Platform3DObject object, bool shouldDeleteObject)
+void WebGLObject::setObject(Platform3DObject object)
{
if (object == m_object)
return;
deleteObject();
m_object = object;
- m_shouldDeleteObject = shouldDeleteObject;
}
void WebGLObject::deleteObject()
{
if (m_object) {
- if (m_shouldDeleteObject)
- if (m_context) {
- m_context->graphicsContext3D()->makeContextCurrent();
- deleteObjectImpl(m_object);
- }
- m_object = 0;
+ if (m_context) {
+ m_context->graphicsContext3D()->makeContextCurrent();
+ deleteObjectImpl(m_object);
+ }
+ if (!m_attachmentCount)
+ m_object = 0;
+ m_deleted = true;
}
- m_shouldDeleteObject = true;
}
}
diff --git a/WebCore/html/canvas/WebGLObject.h b/WebCore/html/canvas/WebGLObject.h
index b66311f..18d4cf9 100644
--- a/WebCore/html/canvas/WebGLObject.h
+++ b/WebCore/html/canvas/WebGLObject.h
@@ -40,7 +40,7 @@ public:
virtual ~WebGLObject();
Platform3DObject object() const { return m_object; }
- void setObject(Platform3DObject, bool shouldDeleteObject = true);
+ void setObject(Platform3DObject);
void deleteObject();
void detachContext()
@@ -58,20 +58,25 @@ public:
virtual bool isShader() const { return false; }
virtual bool isTexture() const { return false; }
+ void onAttached() { ++m_attachmentCount; }
+ void onDetached()
+ {
+ if (m_attachmentCount)
+ --m_attachmentCount;
+ if (!m_attachmentCount && m_deleted)
+ m_object = 0;
+ }
+ unsigned getAttachmentCount() { return m_attachmentCount; }
+
protected:
WebGLObject(WebGLRenderingContext*);
virtual void deleteObjectImpl(Platform3DObject) = 0;
private:
Platform3DObject m_object;
- // The shouldDeleteObject flag indicates whether this wrapper
- // owns the underlying resource and should delete it when the
- // wrapper is unreferenced for the last time and deleted. It
- // is only set to false for certain objects returned from get
- // queries. FIXME: should consider canonicalizing all of these
- // objects in the future.
- bool m_shouldDeleteObject;
WebGLRenderingContext* m_context;
+ unsigned m_attachmentCount;
+ bool m_deleted;
};
} // namespace WebCore
diff --git a/WebCore/html/canvas/WebGLProgram.cpp b/WebCore/html/canvas/WebGLProgram.cpp
index 846b171..8cf3c42 100644
--- a/WebCore/html/canvas/WebGLProgram.cpp
+++ b/WebCore/html/canvas/WebGLProgram.cpp
@@ -45,9 +45,15 @@ WebGLProgram::WebGLProgram(WebGLRenderingContext* ctx)
setObject(context()->graphicsContext3D()->createProgram());
}
-void WebGLProgram::deleteObjectImpl(Platform3DObject object)
+void WebGLProgram::deleteObjectImpl(Platform3DObject obj)
{
- context()->graphicsContext3D()->deleteProgram(object);
+ context()->graphicsContext3D()->deleteProgram(obj);
+ if (!object()) {
+ if (m_vertexShader)
+ m_vertexShader->onDetached();
+ if (m_fragmentShader)
+ m_fragmentShader->onDetached();
+ }
}
bool WebGLProgram::cacheActiveAttribLocations()
@@ -94,6 +100,58 @@ bool WebGLProgram::isUsingVertexAttrib0() const
return false;
}
+WebGLShader* WebGLProgram::getAttachedShader(GraphicsContext3D::WebGLEnumType type)
+{
+ switch (type) {
+ case GraphicsContext3D::VERTEX_SHADER:
+ return m_vertexShader.get();
+ case GraphicsContext3D::FRAGMENT_SHADER:
+ return m_fragmentShader.get();
+ default:
+ return 0;
+ }
+}
+
+bool WebGLProgram::attachShader(WebGLShader* shader)
+{
+ if (!shader || !shader->object())
+ return false;
+ switch (shader->getType()) {
+ case GraphicsContext3D::VERTEX_SHADER:
+ if (m_vertexShader)
+ return false;
+ m_vertexShader = shader;
+ return true;
+ case GraphicsContext3D::FRAGMENT_SHADER:
+ if (m_fragmentShader)
+ return false;
+ m_fragmentShader = shader;
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool WebGLProgram::detachShader(WebGLShader* shader)
+{
+ if (!shader || !shader->object())
+ return false;
+ switch (shader->getType()) {
+ case GraphicsContext3D::VERTEX_SHADER:
+ if (m_vertexShader != shader)
+ return false;
+ m_vertexShader = 0;
+ return true;
+ case GraphicsContext3D::FRAGMENT_SHADER:
+ if (m_fragmentShader != shader)
+ return false;
+ m_fragmentShader = 0;
+ return true;
+ default:
+ return false;
+ }
+}
+
}
#endif // ENABLE(3D_CANVAS)
diff --git a/WebCore/html/canvas/WebGLProgram.h b/WebCore/html/canvas/WebGLProgram.h
index 0156938..e5548eb 100644
--- a/WebCore/html/canvas/WebGLProgram.h
+++ b/WebCore/html/canvas/WebGLProgram.h
@@ -28,6 +28,8 @@
#include "WebGLObject.h"
+#include "WebGLShader.h"
+
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/Vector.h>
@@ -54,6 +56,10 @@ public:
bool isLinkFailureFlagSet() const { return m_linkFailure; }
void setLinkFailureFlag(bool failed) { m_linkFailure = failed; }
+ WebGLShader* getAttachedShader(GraphicsContext3D::WebGLEnumType);
+ bool attachShader(WebGLShader*);
+ bool detachShader(WebGLShader*);
+
protected:
WebGLProgram(WebGLRenderingContext*);
@@ -65,6 +71,9 @@ private:
Vector<int> m_activeAttribLocations;
bool m_linkFailure;
+
+ RefPtr<WebGLShader> m_vertexShader;
+ RefPtr<WebGLShader> m_fragmentShader;
};
} // namespace WebCore
diff --git a/WebCore/html/canvas/WebGLRenderingContext.cpp b/WebCore/html/canvas/WebGLRenderingContext.cpp
index 0284ec6..4465833 100644
--- a/WebCore/html/canvas/WebGLRenderingContext.cpp
+++ b/WebCore/html/canvas/WebGLRenderingContext.cpp
@@ -158,27 +158,11 @@ void WebGLRenderingContext::markContextChanged()
void WebGLRenderingContext::paintRenderingResultsToCanvas()
{
- if (m_markedCanvasDirty) {
- // FIXME: It should not be necessary to clear the image before doing a readback.
- // Investigate why this is needed and remove if possible.
- canvas()->buffer()->clearImage();
- m_markedCanvasDirty = false;
- m_context->paintRenderingResultsToCanvas(this);
- }
-}
-
-void WebGLRenderingContext::beginPaint()
-{
- if (m_markedCanvasDirty)
- m_context->beginPaint(this);
-}
-
-void WebGLRenderingContext::endPaint()
-{
- if (m_markedCanvasDirty) {
- m_markedCanvasDirty = false;
- m_context->endPaint();
- }
+ if (!m_markedCanvasDirty)
+ return;
+ canvas()->clearCopiedImage();
+ m_markedCanvasDirty = false;
+ m_context->paintRenderingResultsToCanvas(this);
}
void WebGLRenderingContext::reshape(int width, int height)
@@ -191,7 +175,9 @@ void WebGLRenderingContext::reshape(int width, int height)
#endif
m_needsUpdate = false;
}
-
+
+ // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off
+ // clear (and this matches what reshape will do).
m_context->reshape(width, height);
}
@@ -217,7 +203,12 @@ void WebGLRenderingContext::attachShader(WebGLProgram* program, WebGLShader* sha
UNUSED_PARAM(ec);
if (!validateWebGLObject(program) || !validateWebGLObject(shader))
return;
+ if (!program->attachShader(shader)) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return;
+ }
m_context->attachShader(objectOrZero(program), objectOrZero(shader));
+ shader->onAttached();
cleanupAfterGraphicsCall(false);
}
@@ -521,6 +512,9 @@ void WebGLRenderingContext::copyTexImage2D(unsigned long target, long level, uns
{
if (!validateTexFuncParameters(target, level, internalformat, width, height, border, internalformat, GraphicsContext3D::UNSIGNED_BYTE))
return;
+ WebGLTexture* tex = validateTextureBinding(target, true);
+ if (!tex)
+ return;
if (!isGLES2Compliant()) {
if (m_framebufferBinding && m_framebufferBinding->object()
&& !isTexInternalFormatColorBufferCombinationValid(internalformat,
@@ -535,21 +529,20 @@ void WebGLRenderingContext::copyTexImage2D(unsigned long target, long level, uns
}
m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
// FIXME: if the framebuffer is not complete, none of the below should be executed.
- WebGLTexture* tex = getTextureBinding(target);
- if (!isGLES2Compliant()) {
- if (tex)
- tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
- }
- if (m_framebufferBinding && tex)
+ if (!isGLES2Compliant())
+ tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
+ if (m_framebufferBinding)
m_framebufferBinding->onAttachedObjectChange(tex);
cleanupAfterGraphicsCall(false);
}
void WebGLRenderingContext::copyTexSubImage2D(unsigned long target, long level, long xoffset, long yoffset, long x, long y, unsigned long width, unsigned long height)
{
+ WebGLTexture* tex = validateTextureBinding(target, true);
+ if (!tex)
+ return;
if (!isGLES2Compliant()) {
- WebGLTexture* tex = getTextureBinding(target);
- if (m_framebufferBinding && m_framebufferBinding->object() && tex
+ if (m_framebufferBinding && m_framebufferBinding->object()
&& !isTexInternalFormatColorBufferCombinationValid(tex->getInternalFormat(),
m_framebufferBinding->getColorBufferFormat())) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
@@ -648,7 +641,12 @@ void WebGLRenderingContext::deleteProgram(WebGLProgram* program)
{
if (!program)
return;
-
+ if (program->context() != this) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return;
+ }
+ if (!program->object())
+ return;
program->deleteObject();
}
@@ -703,7 +701,12 @@ void WebGLRenderingContext::detachShader(WebGLProgram* program, WebGLShader* sha
UNUSED_PARAM(ec);
if (!validateWebGLObject(program) || !validateWebGLObject(shader))
return;
+ if (!program->detachShader(shader)) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return;
+ }
m_context->detachShader(objectOrZero(program), objectOrZero(shader));
+ shader->onDetached();
cleanupAfterGraphicsCall(false);
}
@@ -890,7 +893,7 @@ bool WebGLRenderingContext::validateRenderingState(long numElementsRequired)
bool WebGLRenderingContext::validateWebGLObject(WebGLObject* object)
{
- if (!object) {
+ if (!object || !object->object()) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return false;
}
@@ -1110,22 +1113,18 @@ void WebGLRenderingContext::frontFace(unsigned long mode)
void WebGLRenderingContext::generateMipmap(unsigned long target)
{
- RefPtr<WebGLTexture> tex;
+ WebGLTexture* tex = validateTextureBinding(target, false);
+ if (!tex)
+ return;
if (!isGLES2Compliant()) {
- if (target == GraphicsContext3D::TEXTURE_2D)
- tex = m_textureUnits[m_activeTextureUnit].m_texture2DBinding;
- else if (target == GraphicsContext3D::TEXTURE_CUBE_MAP)
- tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding;
- if (tex && !tex->canGenerateMipmaps()) {
+ if (!tex->canGenerateMipmaps()) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
}
m_context->generateMipmap(target);
- if (!isGLES2Compliant()) {
- if (tex)
- tex->generateMipmapLevelInfo();
- }
+ if (!isGLES2Compliant())
+ tex->generateMipmapLevelInfo();
cleanupAfterGraphicsCall(false);
}
@@ -1574,11 +1573,9 @@ String WebGLRenderingContext::getString(unsigned long name)
WebGLGetInfo WebGLRenderingContext::getTexParameter(unsigned long target, unsigned long pname, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (target != GraphicsContext3D::TEXTURE_2D
- && target != GraphicsContext3D::TEXTURE_CUBE_MAP) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
+ WebGLTexture* tex = validateTextureBinding(target, false);
+ if (!tex)
return WebGLGetInfo();
- }
WebGLStateRestorer(this, false);
int value = 0;
switch (pname) {
@@ -1886,21 +1883,7 @@ void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec
if (!validateWebGLObject(program))
return;
if (!isGLES2Compliant()) {
- Vector<WebGLShader*> shaders;
- bool succeed = getAttachedShaders(program, shaders, ec);
- if (succeed) {
- bool vShader = false;
- bool fShader = false;
- for (size_t ii = 0; ii < shaders.size() && (!vShader || !fShader); ++ii) {
- if (shaders[ii]->getType() == GraphicsContext3D::VERTEX_SHADER)
- vShader = true;
- else if (shaders[ii]->getType() == GraphicsContext3D::FRAGMENT_SHADER)
- fShader = true;
- }
- if (!vShader || !fShader)
- succeed = false;
- }
- if (!succeed) {
+ if (!program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER) || !program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER)) {
program->setLinkFailureFlag(true);
return;
}
@@ -2100,6 +2083,9 @@ void WebGLRenderingContext::texImage2DBase(unsigned target, unsigned level, unsi
ec = 0;
if (!validateTexFuncParameters(target, level, internalformat, width, height, border, format, type))
return;
+ WebGLTexture* tex = validateTextureBinding(target, true);
+ if (!tex)
+ return;
if (!isGLES2Compliant()) {
if (level && WebGLTexture::isNPOT(width, height)) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
@@ -2108,12 +2094,9 @@ void WebGLRenderingContext::texImage2DBase(unsigned target, unsigned level, unsi
}
m_context->texImage2D(target, level, internalformat, width, height,
border, format, type, pixels);
- WebGLTexture* tex = getTextureBinding(target);
- if (!isGLES2Compliant()) {
- if (tex)
- tex->setLevelInfo(target, level, internalformat, width, height, type);
- }
- if (m_framebufferBinding && tex)
+ if (!isGLES2Compliant())
+ tex->setLevelInfo(target, level, internalformat, width, height, type);
+ if (m_framebufferBinding)
m_framebufferBinding->onAttachedObjectChange(tex);
cleanupAfterGraphicsCall(false);
}
@@ -2200,7 +2183,8 @@ void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return;
}
- texImage2DImpl(target, level, internalformat, format, type, canvas->buffer()->image(),
+
+ texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(),
m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
}
@@ -2219,130 +2203,12 @@ void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned
cleanupAfterGraphicsCall(false);
}
-// Obsolete texImage2D entry points -- to be removed shortly. (FIXME)
-
-void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, ImageData* pixels,
- ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texImage2D(GLenum target, GLint level, ImageData pixels)");
- texImage2D(target, level, pixels, 0, 0, ec);
-}
-
-void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, ImageData* pixels,
- bool flipY, ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texImage2D(GLenum target, GLint level, ImageData pixels, GLboolean flipY)");
- texImage2D(target, level, pixels, flipY, 0, ec);
-}
-
-void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, ImageData* pixels,
- bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texImage2D(GLenum target, GLint level, ImageData pixels, GLboolean flipY, GLboolean premultiplyAlpha)");
- ec = 0;
- Vector<uint8_t> data;
- if (!m_context->extractImageData(pixels, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, flipY, premultiplyAlpha, data)) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- texImage2DBase(target, level, GraphicsContext3D::RGBA, pixels->width(), pixels->height(), 0,
- GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, data.data(), ec);
-}
-
-
-void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, HTMLImageElement* image,
- ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texImage2D(GLenum target, GLint level, HTMLImageElement image)");
- texImage2D(target, level, image, 0, 0, ec);
-}
-
-void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, HTMLImageElement* image,
- bool flipY, ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texImage2D(GLenum target, GLint level, HTMLImageElement image, GLboolean flipY)");
- texImage2D(target, level, image, flipY, 0, ec);
-}
-
-void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, HTMLImageElement* image,
- bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texImage2D(GLenum target, GLint level, HTMLImageElement image, GLboolean flipY, GLboolean premultiplyAlpha)");
- ec = 0;
- if (!image || !image->cachedImage()) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- texImage2DImpl(target, level, GraphicsContext3D::RGBA, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, image->cachedImage()->image(), flipY, premultiplyAlpha, ec);
-}
-
-void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas,
- ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texImage2D(GLenum target, GLint level, HTMLCanvasElement canvas)");
- texImage2D(target, level, canvas, 0, 0, ec);
-}
-
-void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas,
- bool flipY, ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texImage2D(GLenum target, GLint level, HTMLCanvasElement canvas, GLboolean flipY)");
- texImage2D(target, level, canvas, flipY, 0, ec);
-}
-
-void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas,
- bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texImage2D(GLenum target, GLint level, HTMLCanvasElement canvas, GLboolean flipY, GLboolean premultiplyAlpha)");
- ec = 0;
- if (!canvas || !canvas->buffer()) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- texImage2DImpl(target, level, GraphicsContext3D::RGBA, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, canvas->buffer()->image(), flipY, premultiplyAlpha, ec);
-}
-
-void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, HTMLVideoElement* video,
- ExceptionCode& ec)
-{
- texImage2D(target, level, video, 0, 0, ec);
-}
-
-void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, HTMLVideoElement* video,
- bool flipY, ExceptionCode& ec)
-{
- texImage2D(target, level, video, flipY, 0, ec);
-}
-
-void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, HTMLVideoElement* video,
- bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
-{
- // FIXME: Need implement this call
- UNUSED_PARAM(target);
- UNUSED_PARAM(level);
- UNUSED_PARAM(video);
- UNUSED_PARAM(flipY);
- UNUSED_PARAM(premultiplyAlpha);
-
- ec = 0;
- cleanupAfterGraphicsCall(false);
-}
-
void WebGLRenderingContext::texParameter(unsigned long target, unsigned long pname, float paramf, int parami, bool isFloat)
{
+ WebGLTexture* tex = validateTextureBinding(target, false);
+ if (!tex)
+ return;
if (!isGLES2Compliant()) {
- RefPtr<WebGLTexture> tex = 0;
- switch (target) {
- case GraphicsContext3D::TEXTURE_2D:
- tex = m_textureUnits[m_activeTextureUnit].m_texture2DBinding;
- break;
- case GraphicsContext3D::TEXTURE_CUBE_MAP:
- tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding;
- break;
- default:
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
- return;
- }
switch (pname) {
case GraphicsContext3D::TEXTURE_MIN_FILTER:
case GraphicsContext3D::TEXTURE_MAG_FILTER:
@@ -2359,12 +2225,10 @@ void WebGLRenderingContext::texParameter(unsigned long target, unsigned long pna
m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
return;
}
- if (tex) {
- if (isFloat)
- tex->setParameterf(pname, paramf);
- else
- tex->setParameteri(pname, parami);
- }
+ if (isFloat)
+ tex->setParameterf(pname, paramf);
+ else
+ tex->setParameteri(pname, parami);
}
if (isFloat)
m_context->texParameterf(target, pname, paramf);
@@ -2391,7 +2255,8 @@ void WebGLRenderingContext::texSubImage2DBase(unsigned target, unsigned level, u
ec = 0;
if (!validateTexFuncFormatAndType(format, type))
return;
-
+ if (!validateTextureBinding(target, true))
+ return;
m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
cleanupAfterGraphicsCall(false);
}
@@ -2469,7 +2334,8 @@ void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsig
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return;
}
- texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->buffer()->image(),
+
+ texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->copiedImage(),
m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
}
@@ -2488,117 +2354,6 @@ void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsig
cleanupAfterGraphicsCall(false);
}
-// Obsolete texSubImage2D entry points -- to be removed shortly. (FIXME)
-
-void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- ImageData* pixels, ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, ImageData pixels)");
- texSubImage2D(target, level, xoffset, yoffset, pixels, 0, 0, ec);
-}
-
-void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- ImageData* pixels, bool flipY, ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, ImageData pixels, GLboolean flipY)");
- texSubImage2D(target, level, xoffset, yoffset, pixels, flipY, 0, ec);
-}
-
-void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- ImageData* pixels, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, ImageData pixels, GLboolean flipY, GLboolean premultiplyAlpha)");
- ec = 0;
- Vector<uint8_t> data;
- if (!m_context->extractImageData(pixels, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, flipY, premultiplyAlpha, data)) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(),
- GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, data.data(), ec);
-}
-
-void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- HTMLImageElement* image, ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, HTMLImageElement image)");
- texSubImage2D(target, level, xoffset, yoffset, image, 0, 0, ec);
-}
-
-void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- HTMLImageElement* image, bool flipY, ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, HTMLImageElement image, GLboolean flipY)");
- texSubImage2D(target, level, xoffset, yoffset, image, flipY, 0, ec);
-}
-
-void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- HTMLImageElement* image, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, HTMLImageElement image, GLboolean flipY, GLboolean premultiplyAlpha)");
- ec = 0;
- if (!image || !image->cachedImage()) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- texSubImage2DImpl(target, level, xoffset, yoffset, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, image->cachedImage()->image(),
- flipY, premultiplyAlpha, ec);
-}
-
-void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- HTMLCanvasElement* canvas, ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, HTMLCanvasElement canvas)");
- texSubImage2D(target, level, xoffset, yoffset, canvas, 0, 0, ec);
-}
-
-void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- HTMLCanvasElement* canvas, bool flipY, ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, HTMLCanvasElement canvas, GLboolean flipY)");
- texSubImage2D(target, level, xoffset, yoffset, canvas, flipY, 0, ec);
-}
-
-void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- HTMLCanvasElement* canvas, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
-{
- printWarningToConsole("Calling obsolete texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, HTMLCanvasElement canvas, GLboolean flipY, GLboolean premultiplyAlpha)");
- ec = 0;
- if (!canvas || !canvas->buffer()) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- texSubImage2DImpl(target, level, xoffset, yoffset, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, canvas->buffer()->image(),
- flipY, premultiplyAlpha, ec);
-}
-
-void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- HTMLVideoElement* video, ExceptionCode& ec)
-{
- texSubImage2D(target, level, xoffset, yoffset, video, 0, 0, ec);
-}
-
-void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- HTMLVideoElement* video, bool flipY, ExceptionCode& ec)
-{
- texSubImage2D(target, level, xoffset, yoffset, video, flipY, 0, ec);
-}
-
-void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
- HTMLVideoElement* video, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
-{
- // FIXME: Need to implement this call
- UNUSED_PARAM(target);
- UNUSED_PARAM(level);
- UNUSED_PARAM(xoffset);
- UNUSED_PARAM(yoffset);
- UNUSED_PARAM(video);
- UNUSED_PARAM(flipY);
- UNUSED_PARAM(premultiplyAlpha);
- ec = 0;
- cleanupAfterGraphicsCall(false);
-}
-
void WebGLRenderingContext::uniform1f(const WebGLUniformLocation* location, float x, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
@@ -2935,13 +2690,23 @@ void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* locatio
void WebGLRenderingContext::useProgram(WebGLProgram* program, ExceptionCode& ec)
{
- UNUSED_PARAM(ec);
if (program && program->context() != this) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
- m_currentProgram = program;
- m_context->useProgram(objectOrZero(program));
+ if (program && program->object() && !getProgramParameter(program, GraphicsContext3D::LINK_STATUS, ec).getBool()) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ cleanupAfterGraphicsCall(false);
+ return;
+ }
+ if (m_currentProgram != program) {
+ if (m_currentProgram)
+ m_currentProgram->onDetached();
+ m_currentProgram = program;
+ m_context->useProgram(objectOrZero(program));
+ if (program)
+ program->onAttached();
+ }
cleanupAfterGraphicsCall(false);
}
@@ -3185,7 +2950,8 @@ WebGLGetInfo WebGLRenderingContext::getUnsignedLongParameter(unsigned long pname
{
int value;
m_context->getIntegerv(pname, &value);
- return WebGLGetInfo(static_cast<unsigned long>(value));
+ unsigned int uValue = static_cast<unsigned int>(value);
+ return WebGLGetInfo(static_cast<unsigned long>(uValue));
}
WebGLGetInfo WebGLRenderingContext::getWebGLFloatArrayParameter(unsigned long pname)
@@ -3309,12 +3075,12 @@ bool WebGLRenderingContext::isTexInternalFormatColorBufferCombinationValid(unsig
return false;
}
-WebGLTexture* WebGLRenderingContext::getTextureBinding(unsigned long target)
+WebGLTexture* WebGLRenderingContext::validateTextureBinding(unsigned long target, bool useSixEnumsForCubeMap)
{
- RefPtr<WebGLTexture> tex = 0;
+ WebGLTexture* tex = 0;
switch (target) {
case GraphicsContext3D::TEXTURE_2D:
- tex = m_textureUnits[m_activeTextureUnit].m_texture2DBinding;
+ tex = m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get();
break;
case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
@@ -3322,12 +3088,26 @@ WebGLTexture* WebGLRenderingContext::getTextureBinding(unsigned long target)
case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
- tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding;
+ if (!useSixEnumsForCubeMap) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
+ return 0;
+ }
+ tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
+ break;
+ case GraphicsContext3D::TEXTURE_CUBE_MAP:
+ if (useSixEnumsForCubeMap) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
+ return 0;
+ }
+ tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
break;
+ default:
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
+ return 0;
}
- if (tex && tex->object())
- return tex.get();
- return 0;
+ if (!tex)
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return tex;
}
bool WebGLRenderingContext::validateTexFuncFormatAndType(unsigned long format, unsigned long type)
diff --git a/WebCore/html/canvas/WebGLRenderingContext.h b/WebCore/html/canvas/WebGLRenderingContext.h
index 608797f..48fa7c8 100644
--- a/WebCore/html/canvas/WebGLRenderingContext.h
+++ b/WebCore/html/canvas/WebGLRenderingContext.h
@@ -206,19 +206,6 @@ public:
unsigned format, unsigned type, HTMLCanvasElement* canvas, ExceptionCode&);
void texImage2D(unsigned target, unsigned level, unsigned internalformat,
unsigned format, unsigned type, HTMLVideoElement* video, ExceptionCode&);
- // Obsolete entry points -- to be removed shortly. (FIXME)
- void texImage2D(unsigned target, unsigned level, ImageData* pixels, ExceptionCode&);
- void texImage2D(unsigned target, unsigned level, ImageData* pixels, bool flipY, ExceptionCode&);
- void texImage2D(unsigned target, unsigned level, ImageData* pixels, bool flipY, bool premultiplyAlpha, ExceptionCode&);
- void texImage2D(unsigned target, unsigned level, HTMLImageElement* image, ExceptionCode&);
- void texImage2D(unsigned target, unsigned level, HTMLImageElement* image, bool flipY, ExceptionCode&);
- void texImage2D(unsigned target, unsigned level, HTMLImageElement* image, bool flipY, bool premultiplyAlpha, ExceptionCode&);
- void texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas, ExceptionCode&);
- void texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas, bool flipY, ExceptionCode&);
- void texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas, bool flipY, bool premultiplyAlpha, ExceptionCode&);
- void texImage2D(unsigned target, unsigned level, HTMLVideoElement* video, ExceptionCode&);
- void texImage2D(unsigned target, unsigned level, HTMLVideoElement* video, bool flipY, ExceptionCode&);
- void texImage2D(unsigned target, unsigned level, HTMLVideoElement* video, bool flipY, bool premultiplyAlpha, ExceptionCode&);
void texParameterf(unsigned target, unsigned pname, float param);
void texParameteri(unsigned target, unsigned pname, int param);
@@ -234,19 +221,6 @@ public:
unsigned format, unsigned type, HTMLCanvasElement* canvas, ExceptionCode&);
void texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
unsigned format, unsigned type, HTMLVideoElement* video, ExceptionCode&);
- // Obsolete entry points -- to be removed shortly. (FIXME)
- void texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, ImageData* pixels, ExceptionCode&);
- void texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, ImageData* pixels, bool flipY, ExceptionCode&);
- void texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, ImageData* pixels, bool flipY, bool premultiplyAlpha, ExceptionCode&);
- void texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, HTMLImageElement* image, ExceptionCode&);
- void texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, HTMLImageElement* image, bool flipY, ExceptionCode&);
- void texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, HTMLImageElement* image, bool flipY, bool premultiplyAlpha, ExceptionCode&);
- void texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, HTMLCanvasElement* canvas, ExceptionCode&);
- void texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, HTMLCanvasElement* canvas, bool flipY, ExceptionCode&);
- void texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, HTMLCanvasElement* canvas, bool flipY, bool premultiplyAlpha, ExceptionCode&);
- void texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, HTMLVideoElement* video, ExceptionCode&);
- void texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, HTMLVideoElement* video, bool flipY, ExceptionCode&);
- void texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset, HTMLVideoElement* video, bool flipY, bool premultiplyAlpha, ExceptionCode&);
void uniform1f(const WebGLUniformLocation* location, float x, ExceptionCode&);
void uniform1fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode&);
@@ -305,12 +279,10 @@ public:
virtual void paintRenderingResultsToCanvas();
- // Helpers for notification about paint events.
- void beginPaint();
- void endPaint();
-
void removeObject(WebGLObject*);
+ bool paintsIntoCanvasBuffer() const { return m_context->paintsIntoCanvasBuffer(); }
+
private:
friend class WebGLObject;
@@ -460,8 +432,10 @@ public:
bool isTexInternalFormatColorBufferCombinationValid(unsigned long texInternalFormat,
unsigned long colorBufferFormat);
- // Helper function to get the current bound texture.
- WebGLTexture* getTextureBinding(unsigned long target);
+ // Helper function to check target and texture bound to the target.
+ // Generate GL errors and return 0 if target is invalid or texture bound is
+ // null. Otherwise, return the texture bound to the target.
+ WebGLTexture* validateTextureBinding(unsigned long target, bool useSixEnumsForCubeMap);
// Helper function to check input format/type for functions {copy}Tex{Sub}Image.
// Generates GL error and returns false if parameters are invalid.
diff --git a/WebCore/html/canvas/WebGLRenderingContext.idl b/WebCore/html/canvas/WebGLRenderingContext.idl
index 711aa42..960dd0b 100644
--- a/WebCore/html/canvas/WebGLRenderingContext.idl
+++ b/WebCore/html/canvas/WebGLRenderingContext.idl
@@ -622,15 +622,6 @@ module html {
in unsigned long format, in unsigned long type, in HTMLCanvasElement canvas) raises (DOMException);
void texImage2D(in unsigned long target, in long level, in unsigned long internalformat,
in unsigned long format, in unsigned long type, in HTMLVideoElement video) raises (DOMException);
- // Obsolete entry points -- to be removed shortly. (FIXME)
- void texImage2D(in unsigned long target, in long level, in ImageData pixels,
- in [Optional] boolean flipY, in [Optional] boolean premultiplyAlpha) raises (DOMException);
- void texImage2D(in unsigned long target, in long level, in HTMLImageElement image,
- in [Optional] boolean flipY, in [Optional] boolean premultiplyAlpha) raises (DOMException);
- void texImage2D(in unsigned long target, in long level, in HTMLCanvasElement canvas,
- in [Optional] boolean flipY, in [Optional] boolean premultiplyAlpha) raises (DOMException);
- void texImage2D(in unsigned long target, in long level, in HTMLVideoElement video,
- in [Optional] boolean flipY, in [Optional] boolean premultiplyAlpha) raises (DOMException);
void texSubImage2D(in unsigned long target, in long level, in long xoffset, in long yoffset,
in long width, in long height,
@@ -643,15 +634,6 @@ module html {
in unsigned long format, in unsigned long type, in HTMLCanvasElement canvas) raises (DOMException);
void texSubImage2D(in unsigned long target, in long level, in long xoffset, in long yoffset,
in unsigned long format, in unsigned long type, in HTMLVideoElement video) raises (DOMException);
- // Obsolete entry points -- to be removed shortly. (FIXME)
- void texSubImage2D(in unsigned long target, in long level, in long xoffset, in long yoffset,
- in ImageData pixels, in [Optional] boolean flipY, in [Optional] boolean premultiplyAlpha) raises (DOMException);
- void texSubImage2D(in unsigned long target, in long level, in long xoffset, in long yoffset,
- in HTMLImageElement image, in [Optional] boolean flipY, in [Optional] boolean premultiplyAlpha) raises (DOMException);
- void texSubImage2D(in unsigned long target, in long level, in long xoffset, in long yoffset,
- in HTMLCanvasElement canvas, in [Optional] boolean flipY, in [Optional] boolean premultiplyAlpha) raises (DOMException);
- void texSubImage2D(in unsigned long target, in long level, in long xoffset, in long yoffset,
- in HTMLVideoElement video, in [Optional] boolean flipY, in [Optional] boolean premultiplyAlpha) raises (DOMException);
void uniform1f(in WebGLUniformLocation location, in float x) raises(DOMException);
[Custom] void uniform1fv(in WebGLUniformLocation location, in Float32Array v) raises(DOMException);
diff --git a/WebCore/html/canvas/WebGLTexture.cpp b/WebCore/html/canvas/WebGLTexture.cpp
index 2c50bf8..e6dfd0a 100644
--- a/WebCore/html/canvas/WebGLTexture.cpp
+++ b/WebCore/html/canvas/WebGLTexture.cpp
@@ -151,21 +151,22 @@ void WebGLTexture::generateMipmapLevelInfo()
return;
if (!canGenerateMipmaps())
return;
- if (m_isComplete)
- return;
- for (size_t ii = 0; ii < m_info.size(); ++ii) {
- const LevelInfo& info0 = m_info[ii][0];
- int width = info0.width;
- int height = info0.height;
- int levelCount = computeLevelCount(width, height);
- for (int level = 1; level < levelCount; ++level) {
- width = std::max(1, width >> 1);
- height = std::max(1, height >> 1);
- LevelInfo& info = m_info[ii][level];
- info.setInfo(info0.internalFormat, width, height, info0.type);
+ if (!m_isComplete) {
+ for (size_t ii = 0; ii < m_info.size(); ++ii) {
+ const LevelInfo& info0 = m_info[ii][0];
+ int width = info0.width;
+ int height = info0.height;
+ int levelCount = computeLevelCount(width, height);
+ for (int level = 1; level < levelCount; ++level) {
+ width = std::max(1, width >> 1);
+ height = std::max(1, height >> 1);
+ LevelInfo& info = m_info[ii][level];
+ info.setInfo(info0.internalFormat, width, height, info0.type);
+ }
}
+ m_isComplete = true;
}
- m_isComplete = true;
+ m_needToUseBlackTexture = false;
}
unsigned long WebGLTexture::getInternalFormat() const