diff options
author | Steve Block <steveblock@google.com> | 2010-04-27 16:31:00 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2010-05-11 14:42:12 +0100 |
commit | dcc8cf2e65d1aa555cce12431a16547e66b469ee (patch) | |
tree | 92a8d65cd5383bca9749f5327fb5e440563926e6 /WebCore/html | |
parent | ccac38a6b48843126402088a309597e682f40fe6 (diff) | |
download | external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.zip external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.tar.gz external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.tar.bz2 |
Merge webkit.org at r58033 : Initial merge by git
Change-Id: If006c38561af287c50cd578d251629b51e4d8cd1
Diffstat (limited to 'WebCore/html')
107 files changed, 3348 insertions, 1000 deletions
diff --git a/WebCore/html/Blob.cpp b/WebCore/html/Blob.cpp index 0b677ea..83bbdc0 100644 --- a/WebCore/html/Blob.cpp +++ b/WebCore/html/Blob.cpp @@ -35,19 +35,84 @@ namespace WebCore { +#if ENABLE(BLOB_SLICE) +const int Blob::toEndOfFile = -1; +const double Blob::doNotCheckFileChange = 0; +#endif + Blob::Blob(const String& path) : m_path(path) +#if ENABLE(BLOB_SLICE) + , m_start(0) + , m_length(toEndOfFile) + , m_snapshotCaptured(false) + , m_snapshotSize(0) + , m_snapshotModificationTime(doNotCheckFileChange) +#endif +{ +} + +#if ENABLE(BLOB_SLICE) +Blob::Blob(const String& path, long long start, long long length, long long snapshotSize, double snapshotModificationTime) + : m_path(path) + , m_start(start) + , m_length(length) + , m_snapshotCaptured(true) + , m_snapshotSize(snapshotSize) + , m_snapshotModificationTime(snapshotModificationTime) { + ASSERT(start >= 0 && length >= 0 && start + length <= snapshotSize && snapshotModificationTime); } +#endif unsigned long long Blob::size() const { // FIXME: JavaScript cannot represent sizes as large as unsigned long long, we need to // come up with an exception to throw if file size is not represetable. +#if ENABLE(BLOB_SLICE) + if (m_snapshotCaptured) + return m_length; +#endif long long size; if (!getFileSize(m_path, size)) return 0; return static_cast<unsigned long long>(size); } +#if ENABLE(BLOB_SLICE) +PassRefPtr<Blob> Blob::slice(long long start, long long length) const +{ + // When we slice a file for the first time, we obtain a snapshot of the file by capturing its current size and modification time. + // The modification time will be used to verify if the file has been changed or not, when the underlying data are accessed. + long long snapshotSize; + double snapshotModificationTime; + if (m_snapshotCaptured) { + snapshotSize = m_snapshotSize; + snapshotModificationTime = m_snapshotModificationTime; + } else { + // If we fail to retrieve the size or modification time, probably due to that the file has been deleted, an empty blob will be returned. + time_t modificationTime; + if (!getFileSize(m_path, snapshotSize) || !getFileModificationTime(m_path, modificationTime)) { + snapshotSize = 0; + snapshotModificationTime = 0; + } else + snapshotModificationTime = modificationTime; + } + + // Clamp the range if it exceeds the size limit. + if (start < 0) + start = 0; + if (length < 0) + length = 0; + + if (start > snapshotSize) { + start = 0; + length = 0; + } else if (start + length > snapshotSize) + length = snapshotSize - start; + + return adoptRef(new Blob(m_path, m_start + start, length, snapshotSize, snapshotModificationTime)); +} +#endif + } // namespace WebCore diff --git a/WebCore/html/Blob.h b/WebCore/html/Blob.h index b910e8f..e8b5f3f 100644 --- a/WebCore/html/Blob.h +++ b/WebCore/html/Blob.h @@ -33,6 +33,7 @@ #include "ExceptionCode.h" #include "PlatformString.h" +#include <time.h> #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> @@ -40,6 +41,11 @@ namespace WebCore { class Blob : public RefCounted<Blob> { public: +#if ENABLE(BLOB_SLICE) + static const int toEndOfFile; + static const double doNotCheckFileChange; +#endif + static PassRefPtr<Blob> create(const String& path) { return adoptRef(new Blob(path)); @@ -47,14 +53,47 @@ public: virtual ~Blob() { } + virtual bool isFile() const { return false; } + +#if ENABLE(BLOB_SLICE) + PassRefPtr<Blob> slice(long long start, long long length) const; +#endif + const String& path() const { return m_path; } unsigned long long size() const; +#if ENABLE(BLOB_SLICE) + long long start() const { return m_start; } + long long length() const { return m_length; } + double modificationTime() const { return m_snapshotModificationTime; } +#endif protected: Blob(const String& path); private: +#if ENABLE(BLOB_SLICE) + Blob(const String& path, long long start, long long length, long long snapshotSize, double snapshotModificationTime); +#endif + + // The underlying path of the file-based blob. String m_path; + +#if ENABLE(BLOB_SLICE) + // The starting position of the file-based blob. + long long m_start; + + // The length of the file-based blob. The value of -1 means to the end of the file. + long long m_length; + + // A flag to tell if a snapshot has been captured. + bool m_snapshotCaptured; + + // The size of the file when a snapshot is captured. It can be 0 if the file is empty. + long long m_snapshotSize; + + // The last modification time of the file when a snapshot is captured. The value of 0 also means that the snapshot is not captured. + double m_snapshotModificationTime; +#endif }; } // namespace WebCore diff --git a/WebCore/html/Blob.idl b/WebCore/html/Blob.idl index 573be35..8db6064 100644 --- a/WebCore/html/Blob.idl +++ b/WebCore/html/Blob.idl @@ -32,6 +32,10 @@ module html { interface Blob { readonly attribute unsigned long long size; + +#if defined(ENABLE_BLOB_SLICE) && ENABLE_BLOB_SLICE + Blob slice(in long long start, in long long length); +#endif }; } diff --git a/WebCore/html/DOMFormData.cpp b/WebCore/html/DOMFormData.cpp new file mode 100644 index 0000000..f848898 --- /dev/null +++ b/WebCore/html/DOMFormData.cpp @@ -0,0 +1,57 @@ +/* + * 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 "DOMFormData.h" + +#include "Blob.h" +#include "PlatformString.h" +#include "TextEncoding.h" + +namespace WebCore { + +DOMFormData::DOMFormData(const TextEncoding& encoding) + : FormDataList(encoding) +{ +} + +void DOMFormData::append(const String& name, const String& value) +{ + if (!name.isEmpty()) + appendData(name, value); +} + +void DOMFormData::append(const String& name, Blob* blob) +{ + if (!name.isEmpty()) + appendBlob(name, blob); +} + +} // namespace WebCore diff --git a/WebCore/html/DOMFormData.h b/WebCore/html/DOMFormData.h new file mode 100644 index 0000000..f071d4a --- /dev/null +++ b/WebCore/html/DOMFormData.h @@ -0,0 +1,58 @@ +/* + * 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 DOMFormData_h +#define DOMFormData_h + +#include "FormDataList.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class Blob; +class String; +class TextEncoding; + +class DOMFormData : public FormDataList, public RefCounted<DOMFormData> { +public: + static PassRefPtr<DOMFormData> create() { return adoptRef(new DOMFormData(UTF8Encoding())); } + static PassRefPtr<DOMFormData> create(const TextEncoding& encoding) { return adoptRef(new DOMFormData(encoding)); } + + void append(const String& name, const String& value); + void append(const String& name, Blob*); + +private: + DOMFormData(const TextEncoding&); +}; + +} // namespace WebCore + +#endif // DOMFormData_h diff --git a/WebCore/html/DOMFormData.idl b/WebCore/html/DOMFormData.idl new file mode 100644 index 0000000..c339381 --- /dev/null +++ b/WebCore/html/DOMFormData.idl @@ -0,0 +1,42 @@ +/* + * 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. + */ + +module html { + + interface [ + CanBeConstructed, + GenerateNativeConverter, + GenerateToJS + ] DOMFormData { + // void append(DOMString name, Blob value); + [Custom] void append(in DOMString name, in DOMString value); + }; + +} diff --git a/WebCore/html/DateComponents.cpp b/WebCore/html/DateComponents.cpp index 9c62d30..39dd733 100644 --- a/WebCore/html/DateComponents.cpp +++ b/WebCore/html/DateComponents.cpp @@ -145,8 +145,8 @@ bool DateComponents::parseYear(const UChar* src, unsigned length, unsigned start static bool beforeGregorianStartDate(int year, int month, int monthDay) { return year < gregorianStartYear - || year == gregorianStartYear && month < gregorianStartMonth - || year == gregorianStartYear && month == gregorianStartMonth && monthDay < gregorianStartDay; + || (year == gregorianStartYear && month < gregorianStartMonth) + || (year == gregorianStartYear && month == gregorianStartMonth && monthDay < gregorianStartDay); } bool DateComponents::addDay(int dayDiff) diff --git a/WebCore/html/File.cpp b/WebCore/html/File.cpp index 25e28e4..97fdc45 100644 --- a/WebCore/html/File.cpp +++ b/WebCore/html/File.cpp @@ -27,6 +27,7 @@ #include "File.h" #include "FileSystem.h" +#include "MIMETypeRegistry.h" namespace WebCore { @@ -34,6 +35,10 @@ File::File(const String& path) : Blob(path) , m_name(pathGetFileName(path)) { + // We don't use MIMETypeRegistry::getMIMETypeForPath() because it returns "application/octet-stream" upon failure. + int index = m_name.reverseFind('.'); + if (index != -1) + m_type = MIMETypeRegistry::getMIMETypeForExtension(m_name.substring(index + 1)); } } // namespace WebCore diff --git a/WebCore/html/File.h b/WebCore/html/File.h index be53e30..065dd86 100644 --- a/WebCore/html/File.h +++ b/WebCore/html/File.h @@ -39,7 +39,10 @@ public: return adoptRef(new File(path)); } + virtual bool isFile() const { return true; } + const String& name() const { return m_name; } + const String& type() const { return m_type; } // FIXME: obsolete attributes. To be removed. const String& fileName() const { return m_name; } @@ -49,6 +52,7 @@ private: File(const String& path); String m_name; + String m_type; }; } // namespace WebCore diff --git a/WebCore/html/File.idl b/WebCore/html/File.idl index 2632a4d..94287ff 100644 --- a/WebCore/html/File.idl +++ b/WebCore/html/File.idl @@ -30,6 +30,7 @@ module html { GenerateToJS ] File : Blob { readonly attribute DOMString name; + readonly attribute DOMString type; // FIXME: obsolete attributes. To be removed. readonly attribute DOMString fileName; diff --git a/WebCore/html/FileStream.cpp b/WebCore/html/FileStream.cpp new file mode 100644 index 0000000..84a28d6 --- /dev/null +++ b/WebCore/html/FileStream.cpp @@ -0,0 +1,105 @@ +/* + * 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" + +#if ENABLE(FILE_READER) || ENABLE(FILE_WRITER) + +#include "FileStream.h" + +#include "Blob.h" +#include "PlatformString.h" + +namespace WebCore { + +FileStream::FileStream(FileStreamClient* client) + : m_client(client) + , m_handle(invalidPlatformFileHandle) +{ +} + +FileStream::~FileStream() +{ + ASSERT(!isHandleValid(m_handle)); +} + +void FileStream::start() +{ + ASSERT(!isMainThread()); + m_client->didStart(); +} + +void FileStream::stop() +{ + ASSERT(!isMainThread()); + close(); + m_client->didStop(); +} + +void FileStream::openForRead(Blob*) +{ + ASSERT(!isMainThread()); + // FIXME: to be implemented. +} + +void FileStream::openForWrite(const String&) +{ + ASSERT(!isMainThread()); + // FIXME: to be implemented. +} + +void FileStream::close() +{ + ASSERT(!isMainThread()); + if (isHandleValid(m_handle)) + closeFile(m_handle); +} + +void FileStream::read(char*, int) +{ + ASSERT(!isMainThread()); + // FIXME: to be implemented. +} + +void FileStream::write(Blob*, long long, int) +{ + ASSERT(!isMainThread()); + // FIXME: to be implemented. +} + +void FileStream::truncate(long long) +{ + ASSERT(!isMainThread()); + // FIXME: to be implemented. +} + +} // namespace WebCore + +#endif // ENABLE(FILE_WRITER) || ENABLE_FILE_READER) diff --git a/WebCore/html/FileStream.h b/WebCore/html/FileStream.h new file mode 100644 index 0000000..bda8fc7 --- /dev/null +++ b/WebCore/html/FileStream.h @@ -0,0 +1,76 @@ +/* + * 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 FileStream_h +#define FileStream_h + +#if ENABLE(FILE_READER) || ENABLE(FILE_WRITER) + +#include "FileStreamClient.h" +#include "FileSystem.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +class Blob; +class String; + +// All methods are synchronous and should be called on File or Worker thread. +class FileStream : public RefCounted<FileStream> { +public: + static PassRefPtr<FileStream> create(FileStreamClient* client) + { + return adoptRef(new FileStream(client)); + } + virtual ~FileStream(); + + void start(); + void stop(); + + void openForRead(Blob*); + void openForWrite(const String& path); + void close(); + void read(char* buffer, int length); + void write(Blob* blob, long long position, int length); + void truncate(long long position); + +private: + FileStream(FileStreamClient*); + + FileStreamClient* m_client; + PlatformFileHandle m_handle; +}; + +} // namespace WebCore + +#endif // ENABLE(FILE_READER) || ENABLE(FILE_WRITER) + +#endif // FileStream_h diff --git a/WebCore/html/FileStreamClient.h b/WebCore/html/FileStreamClient.h new file mode 100644 index 0000000..e1aec53 --- /dev/null +++ b/WebCore/html/FileStreamClient.h @@ -0,0 +1,64 @@ +/* + * 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 FileStreamClient_h +#define FileStreamClient_h + +#if ENABLE(FILE_READER) || ENABLE(FILE_WRITER) + +#include "ExceptionCode.h" +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +class FileStreamClient { +public: + // For reading. + virtual void didRead(const char*, int) { } + + // For writing. + virtual void didWrite(int) { } + + // For both reading and writing. + virtual void didStart() { } + virtual void didStop() { } + virtual void didFinish() { } + virtual void didFail(ExceptionCode) { } + virtual void didGetSize(long long) { } + +protected: + virtual ~FileStreamClient() { } +}; + +} // namespace WebCore + +#endif // ENABLE(FILE_READER) || ENABLE(FILE_WRITER) + +#endif // FileStreamClient_h diff --git a/WebCore/html/FileStreamProxy.cpp b/WebCore/html/FileStreamProxy.cpp new file mode 100644 index 0000000..6b41f32 --- /dev/null +++ b/WebCore/html/FileStreamProxy.cpp @@ -0,0 +1,193 @@ +/* + * 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" + +#if ENABLE(FILE_READER) || ENABLE(FILE_WRITER) + +#include "FileStreamProxy.h" + +#include "Blob.h" +#include "FileStream.h" +#include "FileThread.h" +#include "FileThreadTask.h" +#include "GenericWorkerTask.h" +#include "PlatformString.h" +#include "ScriptExecutionContext.h" + +namespace WebCore { + +FileStreamProxy::FileStreamProxy(ScriptExecutionContext* context, FileStreamClient* client) + : m_context(context) + , m_client(client) + , m_stream(FileStream::create(this)) +{ + // Holds an extra ref so that the instance will not get deleted while there can be any tasks on the file thread. + ref(); + + fileThread()->postTask(createFileThreadTask(m_stream.get(), &FileStream::start)); +} + +FileStreamProxy::~FileStreamProxy() +{ +} + +void FileStreamProxy::openForRead(Blob* blob) +{ + fileThread()->postTask(createFileThreadTask(m_stream.get(), &FileStream::openForRead, blob)); +} + +void FileStreamProxy::openForWrite(const String& path) +{ + fileThread()->postTask(createFileThreadTask(m_stream.get(), &FileStream::openForWrite, path)); +} + +void FileStreamProxy::close() +{ + fileThread()->postTask(createFileThreadTask(m_stream.get(), &FileStream::close)); +} + +void FileStreamProxy::read(char* buffer, int length) +{ + fileThread()->postTask(createFileThreadTask(m_stream.get(), &FileStream::read, buffer, length)); +} + +void FileStreamProxy::write(Blob* blob, long long position, int length) +{ + fileThread()->postTask(createFileThreadTask(m_stream.get(), &FileStream::write, blob, position, length)); +} + +void FileStreamProxy::truncate(long long position) +{ + fileThread()->postTask(createFileThreadTask(m_stream.get(), &FileStream::truncate, position)); +} + +FileThread* FileStreamProxy::fileThread() +{ + ASSERT(m_context->isContextThread()); + ASSERT(m_context->fileThread()); + return m_context->fileThread(); +} + +void FileStreamProxy::stop() +{ + // 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(m_stream.get(), &FileStream::stop)); +} + +static void notifyGetSizeOnContext(ScriptExecutionContext*, FileStreamProxy* proxy, long long size) +{ + if (proxy->client()) + proxy->client()->didGetSize(size); +} + +void FileStreamProxy::didGetSize(long long size) +{ + ASSERT(!m_context->isContextThread()); + m_context->postTask(createCallbackTask(¬ifyGetSizeOnContext, this, size)); +} + +static void notifyReadOnContext(ScriptExecutionContext*, FileStreamProxy* proxy, const char* data, int bytesRead) +{ + if (proxy->client()) + proxy->client()->didRead(data, bytesRead); +} + +void FileStreamProxy::didRead(const char* data, int bytesRead) +{ + ASSERT(!m_context->isContextThread()); + m_context->postTask(createCallbackTask(¬ifyReadOnContext, this, data, bytesRead)); +} + +static void notifyWriteOnContext(ScriptExecutionContext*, FileStreamProxy* proxy, int bytesWritten) +{ + if (proxy->client()) + proxy->client()->didWrite(bytesWritten); +} + +void FileStreamProxy::didWrite(int bytesWritten) +{ + ASSERT(!m_context->isContextThread()); + m_context->postTask(createCallbackTask(¬ifyWriteOnContext, this, bytesWritten)); +} + +static void notifyStartOnContext(ScriptExecutionContext*, FileStreamProxy* proxy) +{ + if (proxy->client()) + proxy->client()->didStart(); +} + +void FileStreamProxy::didStart() +{ + ASSERT(!m_context->isContextThread()); + m_context->postTask(createCallbackTask(¬ifyStartOnContext, this)); +} + +static void notifyFinishOnContext(ScriptExecutionContext*, FileStreamProxy* proxy) +{ + if (proxy->client()) + proxy->client()->didFinish(); +} + +void FileStreamProxy::didFinish() +{ + ASSERT(!m_context->isContextThread()); + m_context->postTask(createCallbackTask(¬ifyFinishOnContext, this)); +} + +static void notifyFailOnContext(ScriptExecutionContext*, FileStreamProxy* proxy, ExceptionCode ec) +{ + if (proxy->client()) + proxy->client()->didFail(ec); +} + +void FileStreamProxy::didFail(ExceptionCode ec) +{ + ASSERT(!m_context->isContextThread()); + m_context->postTask(createCallbackTask(¬ifyFailOnContext, this, ec)); +} + +static void derefProxyOnContext(ScriptExecutionContext*, FileStreamProxy* proxy) +{ + ASSERT(proxy->hasOneRef()); + proxy->deref(); +} + +void FileStreamProxy::didStop() +{ + m_context->postTask(createCallbackTask(&derefProxyOnContext, this)); +} + +} // namespace WebCore + +#endif // ENABLE(FILE_WRITER) diff --git a/WebCore/html/FileStreamProxy.h b/WebCore/html/FileStreamProxy.h new file mode 100644 index 0000000..308da15 --- /dev/null +++ b/WebCore/html/FileStreamProxy.h @@ -0,0 +1,95 @@ +/* + * 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 FileStreamProxy_h +#define FileStreamProxy_h + +#if ENABLE(FILE_READER) || ENABLE(FILE_WRITER) + +#include "ExceptionCode.h" +#include "FileStreamClient.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class Blob; +class FileStream; +class FileThread; +class ScriptExecutionContext; +class String; + +// 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 { +public: + static PassRefPtr<FileStreamProxy> create(ScriptExecutionContext* context, FileStreamClient* client) + { + return adoptRef(new FileStreamProxy(context, client)); + } + virtual ~FileStreamProxy(); + + void openForRead(Blob* blob); + void openForWrite(const String& path); + void close(); + void read(char* buffer, int length); + void write(Blob* 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. + // Note: the caller should deref the instance immediately after calling stop(). + void stop(); + + FileStreamClient* client() const { return m_client; } + +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(); + + RefPtr<ScriptExecutionContext> m_context; + FileStreamClient* m_client; + RefPtr<FileStream> m_stream; +}; + +} // namespace WebCore + +#endif // ENABLE(FILE_READER) || ENABLE(FILE_WRITER) + +#endif // FileStreamProxy_h diff --git a/WebCore/html/FileThread.cpp b/WebCore/html/FileThread.cpp new file mode 100644 index 0000000..02b1718 --- /dev/null +++ b/WebCore/html/FileThread.cpp @@ -0,0 +1,119 @@ +/* + * 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" + +#if ENABLE(FILE_WRITER) || ENABLE(FILE_READER) + +#include "FileThread.h" + +#include "AutodrainedPool.h" +#include "Logging.h" + +namespace WebCore { + +FileThread::FileThread() + : m_threadID(0) +{ + m_selfRef = this; +} + +FileThread::~FileThread() +{ + ASSERT(m_queue.killed()); +} + +bool FileThread::start() +{ + MutexLocker lock(m_threadCreationMutex); + if (m_threadID) + return true; + m_threadID = createThread(FileThread::fileThreadStart, this, "WebCore: File"); + return m_threadID; +} + +void FileThread::stop() +{ + return m_queue.kill(); +} + +void FileThread::postTask(PassOwnPtr<Task> task) +{ + m_queue.append(task); +} + +class SameFilePredicate { +public: + SameFilePredicate(const FileStream* stream) : m_stream(stream) { } + bool operator()(FileThread::Task* task) const { return task->stream() == m_stream; } +private: + const FileStream* m_stream; +}; + +void FileThread::unscheduleTasks(const FileStream* stream) +{ + SameFilePredicate predicate(stream); + m_queue.removeIf(predicate); +} + +void* FileThread::fileThreadStart(void* arg) +{ + FileThread* fileThread = static_cast<FileThread*>(arg); + return fileThread->runLoop(); +} + +void* FileThread::runLoop() +{ + { + // Wait for FileThread::start() to complete to have m_threadID + // established before starting the main loop. + MutexLocker lock(m_threadCreationMutex); + LOG(FileAPI, "Started FileThread %p", this); + } + + AutodrainedPool pool; + while (OwnPtr<Task> task = m_queue.waitForMessage()) { + task->performTask(); + pool.cycle(); + } + + LOG(FileAPI, "About to detach thread %i and clear the ref to FileThread %p, which currently has %i ref(s)", m_threadID, this, refCount()); + + detachThread(m_threadID); + + // Clear the self refptr, possibly resulting in deletion + m_selfRef = 0; + + return 0; +} + +} // namespace WebCore + +#endif // ENABLE(FILE_WRITER) || ENABLE(FILE_READER) diff --git a/WebCore/html/FileThread.h b/WebCore/html/FileThread.h new file mode 100644 index 0000000..d27273a --- /dev/null +++ b/WebCore/html/FileThread.h @@ -0,0 +1,83 @@ +/* + * 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 FileThread_h +#define FileThread_h + +#if ENABLE(FILE_WRITER) || ENABLE(FILE_READER) + +#include <wtf/MessageQueue.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/Threading.h> + +namespace WebCore { + +class FileStream; + +class FileThread : public ThreadSafeShared<FileThread> { +public: + static PassRefPtr<FileThread> create() { return adoptRef(new FileThread()); } + ~FileThread(); + + bool start(); + void stop(); + + class Task : public Noncopyable { + public: + virtual ~Task() { } + virtual void performTask() = 0; + FileStream* stream() const { return m_stream; } + protected: + Task(FileStream* stream) : m_stream(stream) { } + FileStream* m_stream; + }; + + void postTask(PassOwnPtr<Task> task); + void unscheduleTasks(const FileStream*); + +private: + FileThread(); + + static void* fileThreadStart(void*); + void* runLoop(); + + ThreadIdentifier m_threadID; + RefPtr<FileThread> m_selfRef; + MessageQueue<Task> m_queue; + + Mutex m_threadCreationMutex; +}; + +} // namespace WebCore + +#endif // ENABLE(FILE_WRITER) || ENABLE(FILE_READER) + +#endif // FileThread_h diff --git a/WebCore/html/FileThreadTask.h b/WebCore/html/FileThreadTask.h new file mode 100644 index 0000000..f4c59d8 --- /dev/null +++ b/WebCore/html/FileThreadTask.h @@ -0,0 +1,238 @@ +/* + * 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 FileThreadTask_h +#define FileThreadTask_h + +#include "CrossThreadCopier.h" +#include "FileThread.h" +#include <memory> +#include <wtf/PassOwnPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/TypeTraits.h> + +namespace WebCore { + +// Traits for the Task. +template<typename T> struct FileThreadTaskTraits { + typedef const T& ParamType; +}; + +template<typename T> struct FileThreadTaskTraits<T*> { + typedef T* ParamType; +}; + +template<typename T> struct FileThreadTaskTraits<PassRefPtr<T> > { + typedef PassRefPtr<T> ParamType; +}; + +template<typename T> struct FileThreadTaskTraits<PassOwnPtr<T> > { + typedef PassOwnPtr<T> ParamType; +}; + +class FileThreadTask0 : public FileThread::Task { +public: + typedef void (FileStream::*Method)(); + typedef FileThreadTask0 FileThreadTask; + + static PassOwnPtr<FileThreadTask> create(FileStream* stream, Method method) + { + return new FileThreadTask(stream, method); + } + +private: + FileThreadTask0(FileStream* stream, Method method) + : FileThread::Task(stream) + , m_method(method) + { + } + + virtual void performTask() + { + (*stream().*m_method)(); + } + +private: + Method m_method; +}; + +template<typename P1, typename MP1> +class FileThreadTask1 : public FileThread::Task { +public: + typedef void (FileStream::*Method)(MP1); + typedef FileThreadTask1<P1, MP1> FileThreadTask; + typedef typename FileThreadTaskTraits<P1>::ParamType Param1; + + static PassOwnPtr<FileThreadTask> create(FileStream* stream, Method method, Param1 parameter1) + { + return new FileThreadTask(stream, method, parameter1); + } + +private: + FileThreadTask1(FileStream* stream, Method method, Param1 parameter1) + : FileThread::Task(stream) + , m_method(method) + , m_parameter1(parameter1) + { + } + + virtual void performTask() + { + (*stream().*m_method)(m_parameter1); + } + +private: + Method m_method; + P1 m_parameter1; +}; + +template<typename P1, typename MP1, typename P2, typename MP2> +class FileThreadTask2 : public FileThread::Task { +public: + typedef void (FileStream::*Method)(MP1, MP2); + typedef FileThreadTask2<P1, MP1, P2, MP2> FileThreadTask; + typedef typename FileThreadTaskTraits<P1>::ParamType Param1; + typedef typename FileThreadTaskTraits<P2>::ParamType Param2; + + static PassOwnPtr<FileThreadTask> create(FileStream* stream, Method method, Param1 parameter1, Param2 parameter2) + { + return new FileThreadTask(stream, method, parameter1, parameter2); + } + +private: + FileThreadTask2(FileStream* stream, Method method, Param1 parameter1, Param2 parameter2) + : FileThread::Task(stream) + , m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + { + } + + virtual void performTask() + { + (*stream().*m_method)(m_parameter1, m_parameter2); + } + +private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; +}; + +template<typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3> +class FileThreadTask3 : public FileThread::Task { +public: + typedef void (FileStream::*Method)(MP1, MP2, MP3); + typedef FileThreadTask3<P1, MP1, P2, MP2, P3, MP3> FileThreadTask; + typedef typename FileThreadTaskTraits<P1>::ParamType Param1; + typedef typename FileThreadTaskTraits<P2>::ParamType Param2; + typedef typename FileThreadTaskTraits<P3>::ParamType Param3; + + static PassOwnPtr<FileThreadTask> create(FileStream* stream, Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3) + { + return new FileThreadTask(stream, method, parameter1, parameter2, parameter3); + } + +private: + FileThreadTask3(FileStream* stream, Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3) + : FileThread::Task(stream) + , m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + , m_parameter3(parameter3) + { + } + + virtual void performTask() + { + (*stream().*m_method)(m_parameter1, m_parameter2, m_parameter3); + } + +private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; + P3 m_parameter3; +}; + +PassOwnPtr<FileThread::Task> createFileThreadTask( + FileStream* const callee, + void (FileStream::*method)()) +{ + return FileThreadTask0::create( + callee, + method); +} + +template<typename P1, typename MP1> +PassOwnPtr<FileThread::Task> createFileThreadTask( + FileStream* const callee, + void (FileStream::*method)(MP1), + const P1& parameter1) +{ + return FileThreadTask1<typename CrossThreadCopier<P1>::Type, MP1>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1)); +} + +template<typename P1, typename MP1, typename P2, typename MP2> +PassOwnPtr<FileThread::Task> createFileThreadTask( + FileStream* const callee, + void (FileStream::*method)(MP1, MP2), + const P1& parameter1, + const P2& parameter2) +{ + return FileThreadTask2<typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1), + CrossThreadCopier<P2>::copy(parameter2)); +} + +template<typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3> +PassOwnPtr<FileThread::Task> createFileThreadTask( + FileStream* const callee, + void (FileStream::*method)(MP1, MP2, MP3), + const P1& parameter1, + const P2& parameter2, + const P3& parameter3) +{ + return FileThreadTask3<typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2, typename CrossThreadCopier<P3>::Type, MP3>::create( + callee, + method, + CrossThreadCopier<P1>::copy(parameter1), + CrossThreadCopier<P2>::copy(parameter2), + CrossThreadCopier<P3>::copy(parameter3)); +} + +} // namespace WebCore + +#endif // FileThreadTask_h diff --git a/WebCore/html/FormDataList.h b/WebCore/html/FormDataList.h index aec1a52..8ecf64e 100644 --- a/WebCore/html/FormDataList.h +++ b/WebCore/html/FormDataList.h @@ -21,9 +21,9 @@ #ifndef FormDataList_h #define FormDataList_h -#include "CString.h" -#include "File.h" +#include "Blob.h" #include "TextEncoding.h" +#include <wtf/text/CString.h> namespace WebCore { @@ -32,32 +32,45 @@ public: FormDataList(const TextEncoding&); void appendData(const String& key, const String& value) - { appendString(key); appendString(value); } - void appendData(const String& key, const CString& value) - { appendString(key); appendString(value); } + { + appendString(key); + appendString(value); + } + void appendData(const String& key, const WTF::CString& value) + { + appendString(key); + appendString(value); + } void appendData(const String& key, int value) - { appendString(key); appendString(String::number(value)); } - void appendFile(const String& key, PassRefPtr<File> file) - { appendString(key); m_list.append(file); } + { + appendString(key); + appendString(String::number(value)); + } + void appendBlob(const String& key, PassRefPtr<Blob> blob) + { + appendString(key); + m_list.append(blob); + } class Item { public: Item() { } - Item(const CString& data) : m_data(data) { } - Item(PassRefPtr<File> file) : m_file(file) { } + Item(const WTF::CString& data) : m_data(data) { } + Item(PassRefPtr<Blob> blob) : m_blob(blob) { } - const CString& data() const { return m_data; } - File* file() const { return m_file.get(); } + const WTF::CString& data() const { return m_data; } + Blob* blob() const { return m_blob.get(); } private: - CString m_data; - RefPtr<File> m_file; + WTF::CString m_data; + RefPtr<Blob> m_blob; }; const Vector<Item>& list() const { return m_list; } + const TextEncoding& encoding() const { return m_encoding; } private: - void appendString(const CString&); + void appendString(const WTF::CString&); void appendString(const String&); TextEncoding m_encoding; diff --git a/WebCore/html/HTMLAnchorElement.cpp b/WebCore/html/HTMLAnchorElement.cpp index f3b6ddd..f636020 100644 --- a/WebCore/html/HTMLAnchorElement.cpp +++ b/WebCore/html/HTMLAnchorElement.cpp @@ -24,7 +24,6 @@ #include "config.h" #include "HTMLAnchorElement.h" -#include "DNS.h" #include "EventNames.h" #include "Frame.h" #include "FrameLoaderTypes.h" @@ -35,6 +34,7 @@ #include "MouseEvent.h" #include "Page.h" #include "RenderImage.h" +#include "ResourceHandle.h" #include "Settings.h" namespace WebCore { @@ -279,7 +279,7 @@ void HTMLAnchorElement::parseMappedAttribute(MappedAttribute *attr) String parsedURL = deprecatedParseURL(attr->value()); if (document()->isDNSPrefetchEnabled()) { if (protocolIs(parsedURL, "http") || protocolIs(parsedURL, "https") || parsedURL.startsWith("//")) - prefetchDNS(document()->completeURL(parsedURL).host()); + ResourceHandle::prepareForURL(document()->completeURL(parsedURL)); } if (document()->page() && !document()->page()->javaScriptURLsAreAllowed() && protocolIsJavaScript(parsedURL)) { setIsLink(false); diff --git a/WebCore/html/HTMLAppletElement.idl b/WebCore/html/HTMLAppletElement.idl index 8d6803e..f5984f0 100644 --- a/WebCore/html/HTMLAppletElement.idl +++ b/WebCore/html/HTMLAppletElement.idl @@ -23,8 +23,7 @@ module html { interface [ DelegatingPutFunction, DelegatingGetOwnPropertySlot, - CustomCall, - HasOverridingNameGetter + CustomCall ] HTMLAppletElement : HTMLElement { attribute [ConvertNullToNullString, Reflect] DOMString align; attribute [ConvertNullToNullString, Reflect] DOMString alt; diff --git a/WebCore/html/HTMLAttributeNames.in b/WebCore/html/HTMLAttributeNames.in index ad13070..7a353b2 100644 --- a/WebCore/html/HTMLAttributeNames.in +++ b/WebCore/html/HTMLAttributeNames.in @@ -42,7 +42,6 @@ aria-valuemax aria-valuemin aria-valuenow aria-valuetext -autobuffer autocomplete autofocus autoplay @@ -88,6 +87,7 @@ disabled draggable enctype end +event expanded face focused @@ -163,6 +163,8 @@ onemptied onended onerror onfocus +onfocusin +onfocusout onhashchange oninput oninvalid @@ -222,6 +224,7 @@ placeholder pluginurl poster precision +preload primary profile progress diff --git a/WebCore/html/HTMLAudioElement.cpp b/WebCore/html/HTMLAudioElement.cpp index 347b8c4..6018b52 100644 --- a/WebCore/html/HTMLAudioElement.cpp +++ b/WebCore/html/HTMLAudioElement.cpp @@ -44,7 +44,7 @@ HTMLAudioElement::HTMLAudioElement(const QualifiedName& tagName, Document* docum PassRefPtr<HTMLAudioElement> HTMLAudioElement::createForJSConstructor(Document* document, const String& src) { RefPtr<HTMLAudioElement> audio = new HTMLAudioElement(audioTag, document); - audio->setAutobuffer(true); + audio->setPreload("auto"); if (!src.isNull()) { audio->setSrc(src); audio->scheduleLoad(); diff --git a/WebCore/html/HTMLBodyElement.idl b/WebCore/html/HTMLBodyElement.idl index 95140c7..c92dcd3 100644 --- a/WebCore/html/HTMLBodyElement.idl +++ b/WebCore/html/HTMLBodyElement.idl @@ -30,31 +30,31 @@ module html { #if !defined(LANGUAGE_OBJECTIVE_C) || !LANGUAGE_OBJECTIVE_C // Event handler attributes - attribute [DontEnum] EventListener onbeforeunload; - attribute [DontEnum] EventListener onhashchange; - attribute [DontEnum] EventListener onmessage; - attribute [DontEnum] EventListener onoffline; - attribute [DontEnum] EventListener ononline; - attribute [DontEnum] EventListener onpopstate; - attribute [DontEnum] EventListener onresize; - attribute [DontEnum] EventListener onstorage; - attribute [DontEnum] EventListener onunload; + attribute [DontEnum, WindowEventListener] EventListener onbeforeunload; + attribute [DontEnum, WindowEventListener] EventListener onhashchange; + attribute [DontEnum, WindowEventListener] EventListener onmessage; + attribute [DontEnum, WindowEventListener] EventListener onoffline; + attribute [DontEnum, WindowEventListener] EventListener ononline; + attribute [DontEnum, WindowEventListener] EventListener onpopstate; + attribute [DontEnum, WindowEventListener] EventListener onresize; + attribute [DontEnum, WindowEventListener] EventListener onstorage; + attribute [DontEnum, WindowEventListener] EventListener onunload; #if defined(ENABLE_ORIENTATION_EVENTS) && ENABLE_ORIENTATION_EVENTS - attribute [DontEnum] EventListener onorientationchange; + attribute [DontEnum, WindowEventListener] EventListener onorientationchange; #endif - // Overrides of Element attributes (left in for completeness). - // attribute [DontEnum] EventListener onblur; - // attribute [DontEnum] EventListener onerror; - // attribute [DontEnum] EventListener onfocus; - // attribute [DontEnum] EventListener onload; + // Overrides of Element attributes (with different implementation in bindings). + attribute [DontEnum, WindowEventListener] EventListener onblur; + attribute [DontEnum, WindowEventListener] EventListener onerror; + attribute [DontEnum, WindowEventListener] EventListener onfocus; + attribute [DontEnum, WindowEventListener] EventListener onload; // Not implemented yet. - // attribute [DontEnum] EventListener onafterprint; - // attribute [DontEnum] EventListener onbeforeprint; - // attribute [DontEnum] EventListener onredo; - // attribute [DontEnum] EventListener onundo; + // attribute [DontEnum, WindowEventListener] EventListener onafterprint; + // attribute [DontEnum, WindowEventListener] EventListener onbeforeprint; + // attribute [DontEnum, WindowEventListener] EventListener onredo; + // attribute [DontEnum, WindowEventListener] EventListener onundo; #endif }; diff --git a/WebCore/html/HTMLButtonElement.cpp b/WebCore/html/HTMLButtonElement.cpp index 3987859..b3d358d 100644 --- a/WebCore/html/HTMLButtonElement.cpp +++ b/WebCore/html/HTMLButtonElement.cpp @@ -90,10 +90,6 @@ void HTMLButtonElement::parseMappedAttribute(MappedAttribute* attr) } else if (attr->name() == alignAttr) { // Don't map 'align' attribute. This matches what Firefox and IE do, but not Opera. // See http://bugs.webkit.org/show_bug.cgi?id=12071 - } else if (attr->name() == onfocusAttr) { - setAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(this, attr)); - } else if (attr->name() == onblurAttr) { - setAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(this, attr)); } else HTMLFormControlElement::parseMappedAttribute(attr); } diff --git a/WebCore/html/HTMLButtonElement.h b/WebCore/html/HTMLButtonElement.h index f5b9b62..f4df571 100644 --- a/WebCore/html/HTMLButtonElement.h +++ b/WebCore/html/HTMLButtonElement.h @@ -57,11 +57,10 @@ public: String value() const; void setValue(const String&); - virtual bool willValidate() const { return false; } - private: enum Type { SUBMIT, RESET, BUTTON }; virtual bool isOptionalFormControl() const { return true; } + virtual bool recalcWillValidate() const { return false; } Type m_type; bool m_activeSubmit; diff --git a/WebCore/html/HTMLCanvasElement.cpp b/WebCore/html/HTMLCanvasElement.cpp index fa03dbf..0b60949 100644 --- a/WebCore/html/HTMLCanvasElement.cpp +++ b/WebCore/html/HTMLCanvasElement.cpp @@ -28,22 +28,20 @@ #include "HTMLCanvasElement.h" #include "CanvasContextAttributes.h" -#include "CanvasGradient.h" -#include "CanvasPattern.h" #include "CanvasRenderingContext2D.h" #if ENABLE(3D_CANVAS) #include "WebGLContextAttributes.h" #include "WebGLRenderingContext.h" #endif +#include "CanvasGradient.h" +#include "CanvasPattern.h" #include "CanvasStyle.h" #include "Chrome.h" #include "Document.h" -#include "ExceptionCode.h" #include "Frame.h" #include "GraphicsContext.h" #include "HTMLNames.h" #include "ImageBuffer.h" -#include "MIMETypeRegistry.h" #include "MappedAttribute.h" #include "Page.h" #include "RenderHTMLCanvas.h" @@ -55,22 +53,11 @@ namespace WebCore { using namespace HTMLNames; -// These values come from the WhatWG spec. -static const int defaultWidth = 300; -static const int defaultHeight = 150; - -// Firefox limits width/height to 32767 pixels, but slows down dramatically before it -// reaches that limit. We limit by area instead, giving us larger maximum dimensions, -// in exchange for a smaller maximum canvas size. -const float HTMLCanvasElement::MaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pixels - HTMLCanvasElement::HTMLCanvasElement(const QualifiedName& tagName, Document* doc) : HTMLElement(tagName, doc) - , m_size(defaultWidth, defaultHeight) + , CanvasSurface(doc->frame() ? doc->frame()->page()->chrome()->scaleFactor() : 1) , m_observer(0) - , m_originClean(true) , m_ignoreReset(false) - , m_createdImageBuffer(false) { ASSERT(hasTagName(canvasTag)); } @@ -113,8 +100,8 @@ void HTMLCanvasElement::parseMappedAttribute(MappedAttribute* attr) RenderObject* HTMLCanvasElement::createRenderer(RenderArena* arena, RenderStyle* style) { - Settings* settings = document()->settings(); - if (settings && settings->isJavaScriptEnabled()) { + Frame* frame = document()->frame(); + if (frame && frame->script()->canExecuteScripts(NotAboutToExecuteScript)) { m_rendererIsCanvas = true; return new (arena) RenderHTMLCanvas(this); } @@ -133,22 +120,6 @@ void HTMLCanvasElement::setWidth(int value) setAttribute(widthAttr, String::number(value)); } -String HTMLCanvasElement::toDataURL(const String& mimeType, ExceptionCode& ec) -{ - if (!m_originClean) { - ec = SECURITY_ERR; - return String(); - } - - if (m_size.isEmpty() || !buffer()) - return String("data:,"); - - if (mimeType.isNull() || !MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType)) - return buffer()->toDataURL("image/png"); - - return buffer()->toDataURL(mimeType); -} - CanvasRenderingContext* HTMLCanvasElement::getContext(const String& type, CanvasContextAttributes* attrs) { // A Canvas can either be "2D" or "webgl" but never both. If you request a 2D canvas and the existing @@ -162,13 +133,19 @@ CanvasRenderingContext* HTMLCanvasElement::getContext(const String& type, Canvas if (type == "2d") { if (m_context && !m_context->is2d()) return 0; - if (!m_context) - m_context = new CanvasRenderingContext2D(this); + if (!m_context) { + bool usesDashbardCompatibilityMode = false; +#if ENABLE(DASHBOARD_SUPPORT) + if (Settings* settings = document()->settings()) + usesDashbardCompatibilityMode = settings->usesDashboardBackwardCompatibilityMode(); +#endif + m_context = new CanvasRenderingContext2D(this, document()->inCompatMode(), usesDashbardCompatibilityMode); + } return m_context.get(); } #if ENABLE(3D_CANVAS) Settings* settings = document()->settings(); - if (settings && settings->webGLEnabled()) { + if (settings && settings->webGLEnabled() && settings->acceleratedCompositingEnabled()) { // Accept the legacy "webkit-3d" name as well as the provisional "experimental-webgl" name. // Once ratified, we will also accept "webgl" as the context name. if ((type == "webkit-3d") || @@ -193,12 +170,11 @@ CanvasRenderingContext* HTMLCanvasElement::getContext(const String& type, Canvas void HTMLCanvasElement::willDraw(const FloatRect& rect) { - if (m_imageBuffer) - m_imageBuffer->clearImage(); - + CanvasSurface::willDraw(rect); + if (RenderBox* ro = renderBox()) { FloatRect destRect = ro->contentBoxRect(); - FloatRect r = mapRect(rect, FloatRect(0, 0, m_size.width(), m_size.height()), destRect); + FloatRect r = mapRect(rect, FloatRect(0, 0, size().width(), size().height()), destRect); r.intersect(destRect); if (m_dirtyRect.contains(r)) return; @@ -219,28 +195,26 @@ void HTMLCanvasElement::reset() bool ok; int w = getAttribute(widthAttr).toInt(&ok); if (!ok) - w = defaultWidth; + w = DefaultWidth; int h = getAttribute(heightAttr).toInt(&ok); if (!ok) - h = defaultHeight; + h = DefaultHeight; - IntSize oldSize = m_size; - m_size = IntSize(w, h); + IntSize oldSize = size(); + setSurfaceSize(IntSize(w, h)); #if ENABLE(3D_CANVAS) if (m_context && m_context->is3d()) static_cast<WebGLRenderingContext*>(m_context.get())->reshape(width(), height()); #endif - bool hadImageBuffer = m_createdImageBuffer; - m_createdImageBuffer = false; - m_imageBuffer.clear(); + bool hadImageBuffer = hasCreatedImageBuffer(); if (m_context && m_context->is2d()) static_cast<CanvasRenderingContext2D*>(m_context.get())->reset(); if (RenderObject* renderer = this->renderer()) { if (m_rendererIsCanvas) { - if (oldSize != m_size) + if (oldSize != size()) toRenderHTMLCanvas(renderer)->canvasSizeChanged(); if (hadImageBuffer) renderer->repaint(); @@ -267,10 +241,13 @@ void HTMLCanvasElement::paint(GraphicsContext* context, const IntRect& r) } #endif - if (m_imageBuffer) { - Image* image = m_imageBuffer->image(); - if (image) - context->drawImage(image, DeviceColorSpace, r); + if (hasCreatedImageBuffer()) { + ImageBuffer* imageBuffer = buffer(); + if (imageBuffer) { + Image* image = imageBuffer->image(); + if (image) + context->drawImage(image, DeviceColorSpace, r); + } } #if ENABLE(3D_CANVAS) @@ -279,6 +256,7 @@ void HTMLCanvasElement::paint(GraphicsContext* context, const IntRect& r) #endif } +<<<<<<< HEAD IntRect HTMLCanvasElement::convertLogicalToDevice(const FloatRect& logicalRect) const { return IntRect(convertLogicalToDevice(logicalRect.location()), convertLogicalToDevice(logicalRect.size())); @@ -373,6 +351,8 @@ AffineTransform HTMLCanvasElement::baseTransform() const return transform; } +======= +>>>>>>> webkit.org at r58033 #if ENABLE(3D_CANVAS) bool HTMLCanvasElement::is3D() const { diff --git a/WebCore/html/HTMLCanvasElement.h b/WebCore/html/HTMLCanvasElement.h index d70a7e6..b2a76a1 100644 --- a/WebCore/html/HTMLCanvasElement.h +++ b/WebCore/html/HTMLCanvasElement.h @@ -27,7 +27,7 @@ #ifndef HTMLCanvasElement_h #define HTMLCanvasElement_h -#include "AffineTransform.h" +#include "CanvasSurface.h" #include "FloatRect.h" #include "HTMLElement.h" #if ENABLE(3D_CANVAS) @@ -39,13 +39,8 @@ namespace WebCore { class CanvasContextAttributes; class CanvasRenderingContext; -class FloatPoint; -class FloatRect; -class FloatSize; class GraphicsContext; class HTMLCanvasElement; -class ImageBuffer; -class IntPoint; class IntSize; class CanvasObserver { @@ -57,53 +52,38 @@ public: virtual void canvasDestroyed(HTMLCanvasElement*) = 0; }; -class HTMLCanvasElement : public HTMLElement { +class HTMLCanvasElement : public HTMLElement, public CanvasSurface { public: HTMLCanvasElement(const QualifiedName&, Document*); virtual ~HTMLCanvasElement(); - int width() const { return m_size.width(); } - int height() const { return m_size.height(); } void setWidth(int); void setHeight(int); - String toDataURL(const String& mimeType, ExceptionCode&); - CanvasRenderingContext* getContext(const String&, CanvasContextAttributes* attributes = 0); - const IntSize& size() const { return m_size; } - void setSize(const IntSize& size) + void setSize(const IntSize& newSize) { - if (size == m_size) + if (newSize == size()) return; m_ignoreReset = true; - setWidth(size.width()); - setHeight(size.height()); + setWidth(newSize.width()); + setHeight(newSize.height()); m_ignoreReset = false; reset(); } - void willDraw(const FloatRect&); + virtual void willDraw(const FloatRect&); void paint(GraphicsContext*, const IntRect&); - GraphicsContext* drawingContext() const; - - ImageBuffer* buffer() const; - - IntRect convertLogicalToDevice(const FloatRect&) const; - IntSize convertLogicalToDevice(const FloatSize&) const; - IntPoint convertLogicalToDevice(const FloatPoint&) const; - - void setOriginTainted() { m_originClean = false; } - bool originClean() const { return m_originClean; } - void setObserver(CanvasObserver* observer) { m_observer = observer; } - AffineTransform baseTransform() const; - CanvasRenderingContext* renderingContext() const { return m_context.get(); } + RenderBox* renderBox() const { return HTMLElement::renderBox(); } + RenderStyle* computedStyle() { return HTMLElement::computedStyle(); } + #if ENABLE(3D_CANVAS) bool is3D() const; #endif @@ -117,24 +97,15 @@ private: virtual void parseMappedAttribute(MappedAttribute*); virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); - void createImageBuffer() const; void reset(); - static const float MaxCanvasArea; - bool m_rendererIsCanvas; OwnPtr<CanvasRenderingContext> m_context; - IntSize m_size; CanvasObserver* m_observer; - bool m_originClean; bool m_ignoreReset; FloatRect m_dirtyRect; - - // m_createdImageBuffer means we tried to malloc the buffer. We didn't necessarily get it. - mutable bool m_createdImageBuffer; - mutable OwnPtr<ImageBuffer> m_imageBuffer; }; } //namespace diff --git a/WebCore/html/HTMLDocument.cpp b/WebCore/html/HTMLDocument.cpp index cf98755..c0e9eb7 100644 --- a/WebCore/html/HTMLDocument.cpp +++ b/WebCore/html/HTMLDocument.cpp @@ -55,7 +55,6 @@ #include "CSSPropertyNames.h" #include "CSSStyleSelector.h" -#include "CString.h" #include "CookieJar.h" #include "DocumentLoader.h" #include "DocumentType.h" @@ -72,6 +71,7 @@ #include "InspectorController.h" #include "KURL.h" #include "Page.h" +#include <wtf/text/CString.h> #include "DocTypeStrings.cpp" diff --git a/WebCore/html/HTMLElement.cpp b/WebCore/html/HTMLElement.cpp index d3a7f22..816bb60 100644 --- a/WebCore/html/HTMLElement.cpp +++ b/WebCore/html/HTMLElement.cpp @@ -107,6 +107,7 @@ static const TagPriorityMap* createTagPriorityMap() map->add(centerTag.localName().impl(), 5); map->add(footerTag.localName().impl(), 5); map->add(headerTag.localName().impl(), 5); + map->add(hgroupTag.localName().impl(), 5); map->add(nobrTag.localName().impl(), 5); map->add(rubyTag.localName().impl(), 5); map->add(navTag.localName().impl(), 5); @@ -197,6 +198,10 @@ void HTMLElement::parseMappedAttribute(MappedAttribute *attr) setAttributeEventListener(eventNames().mousewheelEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onfocusAttr) { setAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(this, attr)); + } else if (attr->name() == onfocusinAttr) { + setAttributeEventListener(eventNames().focusinEvent, createAttributeEventListener(this, attr)); + } else if (attr->name() == onfocusoutAttr) { + setAttributeEventListener(eventNames().focusoutEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onblurAttr) { setAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onkeydownAttr) { @@ -272,9 +277,9 @@ String HTMLElement::outerHTML() const return createMarkup(this); } -PassRefPtr<DocumentFragment> HTMLElement::createContextualFragment(const String &html, FragmentScriptingPermission scriptingPermission) +PassRefPtr<DocumentFragment> HTMLElement::createContextualFragment(const String& markup, FragmentScriptingPermission scriptingPermission) { - // the following is in accordance with the definition as used by IE + // The following is in accordance with the definition as used by IE. if (endTagRequirement() == TagStatusForbidden) return 0; @@ -282,47 +287,7 @@ PassRefPtr<DocumentFragment> HTMLElement::createContextualFragment(const String hasLocalName(headTag) || hasLocalName(styleTag) || hasLocalName(titleTag)) return 0; - RefPtr<DocumentFragment> fragment = DocumentFragment::create(document()); - - if (document()->isHTMLDocument()) - parseHTMLDocumentFragment(html, fragment.get(), scriptingPermission); - else { - if (!parseXMLDocumentFragment(html, fragment.get(), this, scriptingPermission)) - // FIXME: We should propagate a syntax error exception out here. - return 0; - } - - // Exceptions are ignored because none ought to happen here. - int ignoredExceptionCode; - - // we need to pop <html> and <body> elements and remove <head> to - // accommodate folks passing complete HTML documents to make the - // child of an element. - - RefPtr<Node> nextNode; - for (RefPtr<Node> node = fragment->firstChild(); node; node = nextNode) { - nextNode = node->nextSibling(); - if (node->hasTagName(htmlTag) || node->hasTagName(bodyTag)) { - Node *firstChild = node->firstChild(); - if (firstChild) - nextNode = firstChild; - RefPtr<Node> nextChild; - for (RefPtr<Node> child = firstChild; child; child = nextChild) { - nextChild = child->nextSibling(); - node->removeChild(child.get(), ignoredExceptionCode); - ASSERT(!ignoredExceptionCode); - fragment->insertBefore(child, node.get(), ignoredExceptionCode); - ASSERT(!ignoredExceptionCode); - } - fragment->removeChild(node.get(), ignoredExceptionCode); - ASSERT(!ignoredExceptionCode); - } else if (node->hasTagName(headTag)) { - fragment->removeChild(node.get(), ignoredExceptionCode); - ASSERT(!ignoredExceptionCode); - } - } - - return fragment.release(); + return Element::createContextualFragment(markup, scriptingPermission); } static inline bool hasOneChild(ContainerNode* node) @@ -415,7 +380,7 @@ void HTMLElement::setOuterHTML(const String& html, ExceptionCode& ec) void HTMLElement::setInnerText(const String& text, ExceptionCode& ec) { - // follow the IE specs about when this is allowed + // Follow the IE specs about when this is allowed. if (endTagRequirement() == TagStatusForbidden) { ec = NO_MODIFICATION_ALLOWED_ERR; return; @@ -485,7 +450,7 @@ void HTMLElement::setInnerText(const String& text, ExceptionCode& ec) void HTMLElement::setOuterText(const String &text, ExceptionCode& ec) { - // follow the IE specs about when this is allowed + // Follow the IE specs about when this is allowed. if (endTagRequirement() == TagStatusForbidden) { ec = NO_MODIFICATION_ALLOWED_ERR; return; @@ -513,7 +478,7 @@ void HTMLElement::setOuterText(const String &text, ExceptionCode& ec) if (ec) return; - // is previous node a text node? if so, merge into it + // Is previous node a text node? If so, merge into it. Node* prev = t->previousSibling(); if (prev && prev->isTextNode()) { Text* textPrev = static_cast<Text*>(prev); @@ -526,7 +491,7 @@ void HTMLElement::setOuterText(const String &text, ExceptionCode& ec) t = textPrev; } - // is next node a text node? if so, merge it in + // Is next node a text node? If so, merge it in. Node* next = t->nextSibling(); if (next && next->isTextNode()) { Text* textNext = static_cast<Text*>(next); @@ -566,7 +531,7 @@ Node* HTMLElement::insertAdjacent(const String& where, Node* newChild, Exception return 0; } - // IE throws COM Exception E_INVALIDARG; this is the best DOM exception alternative + // IE throws COM Exception E_INVALIDARG; this is the best DOM exception alternative. ec = NOT_SUPPORTED_ERR; return 0; } @@ -574,7 +539,7 @@ Node* HTMLElement::insertAdjacent(const String& where, Node* newChild, Exception Element* HTMLElement::insertAdjacentElement(const String& where, Element* newChild, ExceptionCode& ec) { if (!newChild) { - // IE throws COM Exception E_INVALIDARG; this is the best DOM exception alternative + // IE throws COM Exception E_INVALIDARG; this is the best DOM exception alternative. ec = TYPE_MISMATCH_ERR; return 0; } @@ -611,8 +576,8 @@ void HTMLElement::addHTMLAlignment(MappedAttribute* attr) void HTMLElement::addHTMLAlignmentToStyledElement(StyledElement* element, MappedAttribute* attr) { - // vertical alignment with respect to the current baseline of the text - // right or left means floating images + // Vertical alignment with respect to the current baseline of the text + // right or left means floating images. int floatValue = CSSValueInvalid; int verticalAlignValue = CSSValueInvalid; @@ -893,6 +858,9 @@ static HashSet<AtomicStringImpl*>* inlineTagList() tagList.add(rpTag.localName().impl()); tagList.add(rtTag.localName().impl()); tagList.add(rubyTag.localName().impl()); +#if ENABLE(PROGRESS_TAG) + tagList.add(progressTag.localName().impl()); +#endif } return &tagList; } @@ -921,6 +889,7 @@ static HashSet<AtomicStringImpl*>* blockTagList() tagList.add(h5Tag.localName().impl()); tagList.add(h6Tag.localName().impl()); tagList.add(headerTag.localName().impl()); + tagList.add(hgroupTag.localName().impl()); tagList.add(hrTag.localName().impl()); tagList.add(isindexTag.localName().impl()); tagList.add(layerTag.localName().impl()); @@ -1011,8 +980,8 @@ bool HTMLElement::rendererIsNeeded(RenderStyle *style) { #if !ENABLE(XHTMLMP) if (hasLocalName(noscriptTag)) { - Settings* settings = document()->settings(); - if (settings && settings->isJavaScriptEnabled()) + Frame* frame = document()->frame(); + if (frame && frame->script()->canExecuteScripts(NotAboutToExecuteScript)) return false; } #endif diff --git a/WebCore/html/HTMLElementsAllInOne.cpp b/WebCore/html/HTMLElementsAllInOne.cpp index f9c970a..4cee927 100644 --- a/WebCore/html/HTMLElementsAllInOne.cpp +++ b/WebCore/html/HTMLElementsAllInOne.cpp @@ -87,6 +87,7 @@ #include "HTMLPlugInElement.cpp" #include "HTMLPlugInImageElement.cpp" #include "HTMLPreElement.cpp" +#include "HTMLProgressElement.cpp" #include "HTMLQuoteElement.cpp" #include "HTMLScriptElement.cpp" #include "HTMLSelectElement.cpp" diff --git a/WebCore/html/HTMLEmbedElement.idl b/WebCore/html/HTMLEmbedElement.idl index d491a0d..576bca9 100644 --- a/WebCore/html/HTMLEmbedElement.idl +++ b/WebCore/html/HTMLEmbedElement.idl @@ -23,8 +23,7 @@ module html { interface [ DelegatingPutFunction, DelegatingGetOwnPropertySlot, - CustomCall, - HasOverridingNameGetter + CustomCall ] HTMLEmbedElement : HTMLElement { attribute [ConvertNullToNullString, Reflect] DOMString align; #if defined(LANGUAGE_JAVASCRIPT) && LANGUAGE_JAVASCRIPT diff --git a/WebCore/html/HTMLFieldSetElement.h b/WebCore/html/HTMLFieldSetElement.h index 0900317..457fe93 100644 --- a/WebCore/html/HTMLFieldSetElement.h +++ b/WebCore/html/HTMLFieldSetElement.h @@ -47,8 +47,8 @@ public: virtual bool supportsFocus() const; virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); virtual const AtomicString& formControlType() const; - - virtual bool willValidate() const { return false; } +private: + virtual bool recalcWillValidate() const { return false; } }; } //namespace diff --git a/WebCore/html/HTMLFormControlElement.cpp b/WebCore/html/HTMLFormControlElement.cpp index 6f24e0c..bcdf40d 100644 --- a/WebCore/html/HTMLFormControlElement.cpp +++ b/WebCore/html/HTMLFormControlElement.cpp @@ -49,14 +49,16 @@ namespace WebCore { using namespace HTMLNames; -HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f) - : HTMLElement(tagName, doc) +HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f, ConstructionType constructionType) + : HTMLElement(tagName, doc, constructionType) , m_form(f) - , m_hasName(false) , m_disabled(false) , m_readOnly(false) , m_required(false) , m_valueMatchesRenderer(false) + , m_willValidateInitialized(false) + , m_willValidate(true) + , m_isValid(true) { if (!m_form) m_form = findFormAncestor(); @@ -90,10 +92,7 @@ ValidityState* HTMLFormControlElement::validity() void HTMLFormControlElement::parseMappedAttribute(MappedAttribute *attr) { - bool oldWillValidate = willValidate(); - if (attr->name() == nameAttr) - m_hasName = !attr->isEmpty(); - else if (attr->name() == disabledAttr) { + if (attr->name() == disabledAttr) { bool oldDisabled = m_disabled; m_disabled = !attr->isNull(); if (oldDisabled != m_disabled) { @@ -112,12 +111,13 @@ void HTMLFormControlElement::parseMappedAttribute(MappedAttribute *attr) } else if (attr->name() == requiredAttr) { bool oldRequired = m_required; m_required = !attr->isNull(); - if (oldRequired != m_required) - setNeedsStyleRecalc(); + if (oldRequired != m_required) { + setNeedsValidityCheck(); + setNeedsStyleRecalc(); // Updates for :required :optional classes. + } } else HTMLElement::parseMappedAttribute(attr); - if (oldWillValidate != willValidate()) - setNeedsWillValidateCheck(); + setNeedsWillValidateCheck(); } void HTMLFormControlElement::attach() @@ -153,10 +153,9 @@ void HTMLFormControlElement::insertedIntoTree(bool deep) // setting a form, we will already have a non-null value for m_form, // and so we don't need to do anything. m_form = findFormAncestor(); - if (m_form) { + if (m_form) m_form->registerFormElement(this); - setNeedsWillValidateCheck(); - } else + else document()->checkedRadioButtons().addButton(this); } @@ -183,19 +182,11 @@ void HTMLFormControlElement::removedFromTree(bool deep) if (m_form && !(parser && parser->isHandlingResidualStyleAcrossBlocks()) && findRoot(this) != findRoot(m_form)) { m_form->removeFormElement(this); m_form = 0; - setNeedsWillValidateCheck(); } HTMLElement::removedFromTree(deep); } -void HTMLFormControlElement::formDestroyed() -{ - if (m_form) - setNeedsWillValidateCheck(); - m_form = 0; -} - const AtomicString& HTMLFormControlElement::formControlName() const { const AtomicString& n = getAttribute(nameAttr); @@ -299,42 +290,74 @@ short HTMLFormControlElement::tabIndex() const return Element::tabIndex(); } -bool HTMLFormControlElement::willValidate() const +bool HTMLFormControlElement::recalcWillValidate() const { - // FIXME: Implementation shall be completed with these checks: - // The control does not have a repetition template as an ancestor. - // The control does not have a datalist element as an ancestor. - // The control is not an output element. - return m_form && m_hasName && !m_disabled && !m_readOnly; + // FIXME: Should return false if this element has a datalist element as an + // ancestor. See HTML5 4.10.10 'The datalist element.' + return !m_disabled && !m_readOnly; } -String HTMLFormControlElement::validationMessage() +bool HTMLFormControlElement::willValidate() const { - return validity()->validationMessage(); + if (!m_willValidateInitialized) { + m_willValidateInitialized = true; + m_willValidate = recalcWillValidate(); + } else { + // If the following assertion fails, setNeedsWillValidateCheck() is not + // called correctly when something which changes recalcWillValidate() result + // is updated. + ASSERT(m_willValidate == recalcWillValidate()); + } + return m_willValidate; } void HTMLFormControlElement::setNeedsWillValidateCheck() { + // We need to recalculate willValidte immediately because willValidate + // change can causes style change. + bool newWillValidate = recalcWillValidate(); + if (m_willValidateInitialized && m_willValidate == newWillValidate) + return; + m_willValidateInitialized = true; + m_willValidate = newWillValidate; setNeedsStyleRecalc(); // FIXME: Show/hide a validation message. } -bool HTMLFormControlElement::checkValidity() +String HTMLFormControlElement::validationMessage() { - if (willValidate() && !isValidFormControlElement()) { - dispatchEvent(Event::create(eventNames().invalidEvent, false, true)); - return false; - } + return validity()->validationMessage(); +} - return true; +bool HTMLFormControlElement::checkValidity(Vector<RefPtr<HTMLFormControlElement> >* unhandledInvalidControls) +{ + if (!willValidate() || isValidFormControlElement()) + return true; + // An event handler can deref this object. + RefPtr<HTMLFormControlElement> protector(this); + RefPtr<Document> originalDocument(document()); + bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true)); + if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument == document()) + unhandledInvalidControls->append(this); + return false; +} + +bool HTMLFormControlElement::isValidFormControlElement() +{ + // If the following assertion fails, setNeedsValidityCheck() is not called + // correctly when something which changes validity is updated. + ASSERT(m_isValid == validity()->valid()); + return m_isValid; } void HTMLFormControlElement::setNeedsValidityCheck() { - if (willValidate()) { + bool newIsValid = validity()->valid(); + if (willValidate() && newIsValid != m_isValid) { // Update style for pseudo classes such as :valid :invalid. setNeedsStyleRecalc(); } + m_isValid = newIsValid; // FIXME: show/hide a validation message. } @@ -345,16 +368,16 @@ void HTMLFormControlElement::setCustomValidity(const String& error) void HTMLFormControlElement::dispatchFocusEvent() { - if (document()->frame() && document()->frame()->page()) - document()->frame()->page()->chrome()->client()->formDidFocus(this); + if (document()->page()) + document()->page()->chrome()->client()->formDidFocus(this); HTMLElement::dispatchFocusEvent(); } void HTMLFormControlElement::dispatchBlurEvent() { - if (document()->frame() && document()->frame()->page()) - document()->frame()->page()->chrome()->client()->formDidBlur(this); + if (document()->page()) + document()->page()->chrome()->client()->formDidBlur(this); HTMLElement::dispatchBlurEvent(); } @@ -369,11 +392,6 @@ bool HTMLFormControlElement::isDefaultButtonForForm() const return isSuccessfulSubmitButton() && m_form && m_form->defaultButton() == this; } -bool HTMLFormControlElement::isValidFormControlElement() -{ - return validity()->valid(); -} - void HTMLFormControlElement::removeFromForm() { if (!m_form) @@ -405,9 +423,29 @@ void HTMLFormControlElementWithState::didMoveToNewOwnerDocument() HTMLFormControlElement::didMoveToNewOwnerDocument(); } +bool HTMLFormControlElementWithState::autoComplete() const +{ + if (!form()) + return true; + return form()->autoComplete(); +} + +bool HTMLFormControlElementWithState::shouldSaveAndRestoreFormControlState() const +{ + // We don't save/restore control state in a form with autocomplete=off. + return autoComplete(); +} + void HTMLFormControlElementWithState::finishParsingChildren() { HTMLFormControlElement::finishParsingChildren(); + + // We don't save state of a control with shouldSaveAndRestoreFormControlState()=false. + // But we need to skip restoring process too because a control in another + // form might have the same pair of name and type and saved its state. + if (!shouldSaveAndRestoreFormControlState()) + return; + Document* doc = document(); if (doc->hasStateForNewFormElements()) { String state; @@ -520,10 +558,6 @@ void HTMLTextFormControlElement::parseMappedAttribute(MappedAttribute* attr) { if (attr->name() == placeholderAttr) updatePlaceholderVisibility(true); - else if (attr->name() == onfocusAttr) - setAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(this, attr)); - else if (attr->name() == onblurAttr) - setAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(this, attr)); else if (attr->name() == onselectAttr) setAttributeEventListener(eventNames().selectEvent, createAttributeEventListener(this, attr)); else if (attr->name() == onchangeAttr) diff --git a/WebCore/html/HTMLFormControlElement.h b/WebCore/html/HTMLFormControlElement.h index 117087b..0045fbe 100644 --- a/WebCore/html/HTMLFormControlElement.h +++ b/WebCore/html/HTMLFormControlElement.h @@ -36,7 +36,7 @@ class VisibleSelection; class HTMLFormControlElement : public HTMLElement { public: - HTMLFormControlElement(const QualifiedName& tagName, Document*, HTMLFormElement*); + HTMLFormControlElement(const QualifiedName& tagName, Document*, HTMLFormElement*, ConstructionType = CreateElementZeroRefCount); virtual ~HTMLFormControlElement(); virtual HTMLTagStatus endTagRequirement() const { return TagStatusRequired; } @@ -108,7 +108,7 @@ public: virtual bool willValidate() const; String validationMessage(); - bool checkValidity(); + bool checkValidity(Vector<RefPtr<HTMLFormControlElement> >* unhandledInvalidControls = 0); // This must be called when a validation constraint or control value is changed. void setNeedsValidityCheck(); void setCustomValidity(const String&); @@ -116,7 +116,7 @@ public: virtual bool patternMismatch() const { return false; } virtual bool tooLong() const { return false; } - void formDestroyed(); + void formDestroyed() { m_form = 0; } virtual void dispatchFocusEvent(); virtual void dispatchBlurEvent(); @@ -125,6 +125,7 @@ protected: void removeFromForm(); // This must be called any time the result of willValidate() has changed. void setNeedsWillValidateCheck(); + virtual bool recalcWillValidate() const; private: virtual HTMLFormElement* virtualForm() const; @@ -133,11 +134,18 @@ private: HTMLFormElement* m_form; OwnPtr<ValidityState> m_validityState; - bool m_hasName : 1; bool m_disabled : 1; bool m_readOnly : 1; bool m_required : 1; bool m_valueMatchesRenderer : 1; + // The initial value of m_willValidate depends on a subclass, and we can't + // initialize it with a virtual function in the constructor. m_willValidate + // is not deterministic during m_willValidateInitialized=false. + mutable bool m_willValidateInitialized: 1; + mutable bool m_willValidate : 1; + // Cache of validity()->valid(). + // "candidate for constraint validation" doesn't affect to m_isValid. + bool m_isValid : 1; }; class HTMLFormControlElementWithState : public HTMLFormControlElement { @@ -145,6 +153,8 @@ public: HTMLFormControlElementWithState(const QualifiedName& tagName, Document*, HTMLFormElement*); virtual ~HTMLFormControlElementWithState(); + virtual bool autoComplete() const; + virtual bool shouldSaveAndRestoreFormControlState() const; virtual void finishParsingChildren(); protected: diff --git a/WebCore/html/HTMLFormElement.cpp b/WebCore/html/HTMLFormElement.cpp index 2f88894..cafa3c9 100644 --- a/WebCore/html/HTMLFormElement.cpp +++ b/WebCore/html/HTMLFormElement.cpp @@ -26,8 +26,8 @@ #include "HTMLFormElement.h" #include "CSSHelper.h" -#include "Chrome.h" -#include "ChromeClient.h" +#include "DOMFormData.h" +#include "DOMWindow.h" #include "Document.h" #include "Event.h" #include "EventNames.h" @@ -46,7 +46,6 @@ #include "ScriptEventListener.h" #include "MIMETypeRegistry.h" #include "MappedAttribute.h" -#include "Page.h" #include "RenderTextControl.h" #include "ValidityState.h" #include <limits> @@ -201,83 +200,16 @@ TextEncoding HTMLFormElement::dataEncoding() const return m_formDataBuilder.dataEncoding(document()); } -PassRefPtr<FormData> HTMLFormElement::createFormData(const CString& boundary) +PassRefPtr<FormData> HTMLFormElement::createFormData() { - Vector<char> encodedData; - TextEncoding encoding = dataEncoding().encodingForFormSubmission(); - - RefPtr<FormData> result = FormData::create(); - + RefPtr<DOMFormData> domFormData = DOMFormData::create(dataEncoding().encodingForFormSubmission()); for (unsigned i = 0; i < formElements.size(); ++i) { HTMLFormControlElement* control = formElements[i]; - FormDataList list(encoding); - - if (!control->disabled() && control->appendFormData(list, m_formDataBuilder.isMultiPartForm())) { - size_t formDataListSize = list.list().size(); - ASSERT(formDataListSize % 2 == 0); - for (size_t j = 0; j < formDataListSize; j += 2) { - const FormDataList::Item& key = list.list()[j]; - const FormDataList::Item& value = list.list()[j + 1]; - if (!m_formDataBuilder.isMultiPartForm()) { - // Omit the name "isindex" if it's the first form data element. - // FIXME: Why is this a good rule? Is this obsolete now? - if (encodedData.isEmpty() && key.data() == "isindex") - FormDataBuilder::encodeStringAsFormData(encodedData, value.data()); - else - m_formDataBuilder.addKeyValuePairAsFormData(encodedData, key.data(), value.data()); - } else { - Vector<char> header; - m_formDataBuilder.beginMultiPartHeader(header, boundary, key.data()); - - bool shouldGenerateFile = false; - // if the current type is FILE, then we also need to include the filename - if (value.file()) { - const String& path = value.file()->path(); - String fileName = value.file()->fileName(); - - // Let the application specify a filename if it's going to generate a replacement file for the upload. - if (!path.isEmpty()) { - if (Page* page = document()->page()) { - String generatedFileName; - shouldGenerateFile = page->chrome()->client()->shouldReplaceWithGeneratedFileForUpload(path, generatedFileName); - if (shouldGenerateFile) - fileName = generatedFileName; - } - } - - // We have to include the filename=".." part in the header, even if the filename is empty - m_formDataBuilder.addFilenameToMultiPartHeader(header, encoding, fileName); - - if (!fileName.isEmpty()) { - // FIXME: The MIMETypeRegistry function's name makes it sound like it takes a path, - // not just a basename. But filename is not the path. But note that it's not safe to - // just use path instead since in the generated-file case it will not reflect the - // MIME type of the generated file. - String mimeType = MIMETypeRegistry::getMIMETypeForPath(fileName); - if (!mimeType.isEmpty()) - m_formDataBuilder.addContentTypeToMultiPartHeader(header, mimeType.latin1()); - } - } - - m_formDataBuilder.finishMultiPartHeader(header); - - // Append body - result->appendData(header.data(), header.size()); - if (size_t dataSize = value.data().length()) - result->appendData(value.data().data(), dataSize); - else if (value.file() && !value.file()->path().isEmpty()) - result->appendFile(value.file()->path(), shouldGenerateFile); - - result->appendData("\r\n", 2); - } - } - } + if (!control->disabled()) + control->appendFormData(*domFormData, m_formDataBuilder.isMultiPartForm()); } - if (m_formDataBuilder.isMultiPartForm()) - m_formDataBuilder.addBoundaryToMultiPartHeader(encodedData, boundary, true); - - result->appendData(encodedData.data(), encodedData.size()); + RefPtr<FormData> result = (m_formDataBuilder.isMultiPartForm()) ? FormData::createMultiPart(*domFormData, document()) : FormData::create(*domFormData); result->setIdentifier(generateFormDataIdentifier()); return result; @@ -288,6 +220,64 @@ bool HTMLFormElement::isMailtoForm() const return protocolIs(m_url, "mailto"); } +static inline HTMLFormControlElement* submitElementFromEvent(const Event* event) +{ + Node* targetNode = event->target()->toNode(); + if (!targetNode || !targetNode->isElementNode()) + return 0; + Element* targetElement = static_cast<Element*>(targetNode); + if (!targetElement->isFormControlElement()) + return 0; + return static_cast<HTMLFormControlElement*>(targetElement); +} + +bool HTMLFormElement::validateInteractively(Event* event) +{ + ASSERT(event); + if (noValidate()) + return true; + + HTMLFormControlElement* submitElement = submitElementFromEvent(event); + if (submitElement && submitElement->formNoValidate()) + return true; + + Vector<RefPtr<HTMLFormControlElement> > unhandledInvalidControls; + collectUnhandledInvalidControls(unhandledInvalidControls); + if (unhandledInvalidControls.isEmpty()) + return true; + // If the form has invalid controls, abort submission. + + RefPtr<HTMLFormElement> protector(this); + // Focus on the first focusable control. + for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) { + HTMLFormControlElement* unhandled = unhandledInvalidControls[i].get(); + if (unhandled->isFocusable() && unhandled->inDocument()) { + RefPtr<Document> originalDocument(unhandled->document()); + unhandled->scrollIntoViewIfNeeded(false); + // scrollIntoViewIfNeeded() dispatches events, so the state + // of 'unhandled' might be changed so it's no longer focusable or + // moved to another document. + if (unhandled->isFocusable() && unhandled->inDocument() && originalDocument == unhandled->document()) { + unhandled->focus(); + break; + } + } + } + // Warn about all of unfocusable controls. + if (Frame* frame = document()->frame()) { + for (unsigned i = 0; i < unhandledInvalidControls.size(); ++i) { + HTMLFormControlElement* unhandled = unhandledInvalidControls[i].get(); + if (unhandled->isFocusable() && unhandled->inDocument()) + continue; + String message("An invalid form control with name='%name' is not focusable."); + message.replace("%name", unhandled->name()); + frame->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, ErrorMessageLevel, message, 0, document()->url().string()); + } + } + m_insubmit = false; + return false; +} + bool HTMLFormElement::prepareSubmit(Event* event) { Frame* frame = document()->frame(); @@ -297,6 +287,10 @@ bool HTMLFormElement::prepareSubmit(Event* event) m_insubmit = true; m_doingsubmit = false; + // Interactive validation must be done before dispatching the submit event. + if (!validateInteractively(event)) + return false; + if (dispatchEvent(Event::create(eventNames().submitEvent, true, true)) && !m_doingsubmit) m_doingsubmit = true; @@ -389,8 +383,8 @@ void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool lockH ASSERT(!m_formDataBuilder.isMultiPartForm()); } + RefPtr<FormData> data = createFormData(); if (!m_formDataBuilder.isMultiPartForm()) { - RefPtr<FormData> data = createFormData(CString()); if (isMailtoForm()) { // Convert the form data into a string that we put into the URL. @@ -400,13 +394,11 @@ void HTMLFormElement::submit(Event* event, bool activateSubmitButton, bool lockH } frame->loader()->submitForm("POST", m_url, data.release(), m_target, m_formDataBuilder.encodingType(), String(), lockHistory, event, formState.release()); - } else { - Vector<char> boundary = m_formDataBuilder.generateUniqueBoundaryString(); - frame->loader()->submitForm("POST", m_url, createFormData(boundary.data()), m_target, m_formDataBuilder.encodingType(), boundary.data(), lockHistory, event, formState.release()); - } + } else + frame->loader()->submitForm("POST", m_url, data.get(), m_target, m_formDataBuilder.encodingType(), data->boundary().data(), lockHistory, event, formState.release()); } else { m_formDataBuilder.setIsMultiPartForm(false); - frame->loader()->submitForm("GET", m_url, createFormData(CString()), m_target, String(), String(), lockHistory, event, formState.release()); + frame->loader()->submitForm("GET", m_url, createFormData(), m_target, String(), String(), lockHistory, event, formState.release()); } if (needButtonActivation && firstSuccessfulSubmitButton) @@ -612,16 +604,24 @@ HTMLFormControlElement* HTMLFormElement::defaultButton() const bool HTMLFormElement::checkValidity() { - // TODO: Check for unhandled invalid controls, see #27452 for tips. + Vector<RefPtr<HTMLFormControlElement> > controls; + collectUnhandledInvalidControls(controls); + return controls.isEmpty(); +} - bool hasOnlyValidControls = true; - for (unsigned i = 0; i < formElements.size(); ++i) { - HTMLFormControlElement* control = formElements[i]; - if (!control->checkValidity()) - hasOnlyValidControls = false; +void HTMLFormElement::collectUnhandledInvalidControls(Vector<RefPtr<HTMLFormControlElement> >& unhandledInvalidControls) +{ + RefPtr<HTMLFormElement> protector(this); + // Copy formElements because event handlers called from + // HTMLFormControlElement::checkValidity() might change formElements. + Vector<RefPtr<HTMLFormControlElement> > elements; + elements.reserveCapacity(formElements.size()); + for (unsigned i = 0; i < formElements.size(); ++i) + elements.append(formElements[i]); + for (unsigned i = 0; i < elements.size(); ++i) { + if (elements[i]->form() == this) + elements[i]->checkValidity(&unhandledInvalidControls); } - - return hasOnlyValidControls; } PassRefPtr<HTMLFormControlElement> HTMLFormElement::elementForAlias(const AtomicString& alias) diff --git a/WebCore/html/HTMLFormElement.h b/WebCore/html/HTMLFormElement.h index c0ce3e3..923c734 100644 --- a/WebCore/html/HTMLFormElement.h +++ b/WebCore/html/HTMLFormElement.h @@ -135,8 +135,13 @@ private: bool isMailtoForm() const; TextEncoding dataEncoding() const; - PassRefPtr<FormData> createFormData(const CString& boundary); + PassRefPtr<FormData> createFormData(); unsigned formElementIndex(HTMLFormControlElement*); + // Returns true if the submission should be proceeded. + bool validateInteractively(Event*); + // Validates each of the controls, and stores controls of which 'invalid' + // event was not canceled to the specified vector. + void collectUnhandledInvalidControls(Vector<RefPtr<HTMLFormControlElement> >&); friend class HTMLFormCollection; diff --git a/WebCore/html/HTMLFrameElementBase.cpp b/WebCore/html/HTMLFrameElementBase.cpp index 9d84b62..76f3ed4 100644 --- a/WebCore/html/HTMLFrameElementBase.cpp +++ b/WebCore/html/HTMLFrameElementBase.cpp @@ -90,7 +90,7 @@ bool HTMLFrameElementBase::isURLAllowed() const return true; } -void HTMLFrameElementBase::openURL() +void HTMLFrameElementBase::openURL(bool lockHistory, bool lockBackForwardList) { ASSERT(!m_frameName.isEmpty()); @@ -104,7 +104,7 @@ void HTMLFrameElementBase::openURL() if (!parentFrame) return; - parentFrame->loader()->requestFrame(this, m_URL, m_frameName); + parentFrame->loader()->requestFrame(this, m_URL, m_frameName, lockHistory, lockBackForwardList); if (contentFrame()) contentFrame()->setInViewSourceMode(viewSourceMode()); } @@ -231,7 +231,7 @@ void HTMLFrameElementBase::setLocation(const String& str) m_URL = AtomicString(str); if (inDocument()) - openURL(); + openURL(false, false); } bool HTMLFrameElementBase::supportsFocus() const diff --git a/WebCore/html/HTMLFrameElementBase.h b/WebCore/html/HTMLFrameElementBase.h index 7717df0..6424ba7 100644 --- a/WebCore/html/HTMLFrameElementBase.h +++ b/WebCore/html/HTMLFrameElementBase.h @@ -73,7 +73,7 @@ private: bool viewSourceMode() const { return m_viewSource; } void setNameAndOpenURL(); - void openURL(); + void openURL(bool lockHistory = true, bool lockBackForwardList = true); static void setNameAndOpenURLCallback(Node*); diff --git a/WebCore/html/HTMLFrameSetElement.cpp b/WebCore/html/HTMLFrameSetElement.cpp index f4d1558..9cc4975 100644 --- a/WebCore/html/HTMLFrameSetElement.cpp +++ b/WebCore/html/HTMLFrameSetElement.cpp @@ -135,6 +135,10 @@ void HTMLFrameSetElement::parseMappedAttribute(MappedAttribute *attr) document()->setWindowAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(document()->frame(), attr)); else if (attr->name() == onfocusAttr) document()->setWindowAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(document()->frame(), attr)); + else if (attr->name() == onfocusinAttr) + document()->setWindowAttributeEventListener(eventNames().focusinEvent, createAttributeEventListener(document()->frame(), attr)); + else if (attr->name() == onfocusoutAttr) + document()->setWindowAttributeEventListener(eventNames().focusoutEvent, createAttributeEventListener(document()->frame(), attr)); #if ENABLE(ORIENTATION_EVENTS) else if (attr->name() == onorientationchangeAttr) document()->setWindowAttributeEventListener(eventNames().orientationchangeEvent, createAttributeEventListener(document()->frame(), attr)); diff --git a/WebCore/html/HTMLFrameSetElement.idl b/WebCore/html/HTMLFrameSetElement.idl index 3a761ae..9763460 100644 --- a/WebCore/html/HTMLFrameSetElement.idl +++ b/WebCore/html/HTMLFrameSetElement.idl @@ -28,31 +28,31 @@ module html { #if !defined(LANGUAGE_OBJECTIVE_C) || !LANGUAGE_OBJECTIVE_C // Event handler attributes - attribute [DontEnum] EventListener onbeforeunload; - attribute [DontEnum] EventListener onhashchange; - attribute [DontEnum] EventListener onmessage; - attribute [DontEnum] EventListener onoffline; - attribute [DontEnum] EventListener ononline; - attribute [DontEnum] EventListener onpopstate; - attribute [DontEnum] EventListener onresize; - attribute [DontEnum] EventListener onstorage; - attribute [DontEnum] EventListener onunload; + attribute [DontEnum, WindowEventListener] EventListener onbeforeunload; + attribute [DontEnum, WindowEventListener] EventListener onhashchange; + attribute [DontEnum, WindowEventListener] EventListener onmessage; + attribute [DontEnum, WindowEventListener] EventListener onoffline; + attribute [DontEnum, WindowEventListener] EventListener ononline; + attribute [DontEnum, WindowEventListener] EventListener onpopstate; + attribute [DontEnum, WindowEventListener] EventListener onresize; + attribute [DontEnum, WindowEventListener] EventListener onstorage; + attribute [DontEnum, WindowEventListener] EventListener onunload; #if defined(ENABLE_ORIENTATION_EVENTS) && ENABLE_ORIENTATION_EVENTS attribute [DontEnum] EventListener onorientationchange; #endif - // Overrides of Element attributes (left in for completeness). - // attribute [DontEnum] EventListener onblur; - // attribute [DontEnum] EventListener onerror; - // attribute [DontEnum] EventListener onfocus; - // attribute [DontEnum] EventListener onload; + // Overrides of Element attributes (with different implementation in bindings). + attribute [DontEnum, WindowEventListener] EventListener onblur; + attribute [DontEnum, WindowEventListener] EventListener onerror; + attribute [DontEnum, WindowEventListener] EventListener onfocus; + attribute [DontEnum, WindowEventListener] EventListener onload; // Not implemented yet. - // attribute [DontEnum] EventListener onafterprint; - // attribute [DontEnum] EventListener onbeforeprint; - // attribute [DontEnum] EventListener onredo; - // attribute [DontEnum] EventListener onundo; + // attribute [DontEnum, WindowEventListener] EventListener onafterprint; + // attribute [DontEnum, WindowEventListener] EventListener onbeforeprint; + // attribute [DontEnum, WindowEventListener] EventListener onredo; + // attribute [DontEnum, WindowEventListener] EventListener onundo; #endif }; diff --git a/WebCore/html/HTMLIFrameElement.cpp b/WebCore/html/HTMLIFrameElement.cpp index 359bdb7..cce39df 100644 --- a/WebCore/html/HTMLIFrameElement.cpp +++ b/WebCore/html/HTMLIFrameElement.cpp @@ -30,7 +30,7 @@ #include "HTMLDocument.h" #include "HTMLNames.h" #include "MappedAttribute.h" -#include "RenderPartObject.h" +#include "RenderIFrame.h" namespace WebCore { @@ -67,6 +67,7 @@ bool HTMLIFrameElement::mapToEntry(const QualifiedName& attrName, MappedAttribut return HTMLFrameElementBase::mapToEntry(attrName, result); } +#if ENABLE(SANDBOX) static SandboxFlags parseSandboxAttribute(MappedAttribute* attribute) { if (attribute->isNull()) @@ -94,12 +95,15 @@ static SandboxFlags parseSandboxAttribute(MappedAttribute* attribute) flags &= ~SandboxForms; else if (equalIgnoringCase(sandboxToken, "allow-scripts")) flags &= ~SandboxScripts; + else if (equalIgnoringCase(sandboxToken, "allow-top-navigation")) + flags &= ~SandboxTopNavigation; start = end + 1; } - + return flags; } +#endif void HTMLIFrameElement::parseMappedAttribute(MappedAttribute* attr) { @@ -123,8 +127,11 @@ void HTMLIFrameElement::parseMappedAttribute(MappedAttribute* attr) if (!attr->isNull() && !attr->value().toInt()) // Add a rule that nulls out our border width. addCSSLength(attr, CSSPropertyBorderWidth, "0"); - } else if (attr->name() == sandboxAttr) + } +#if ENABLE(SANDBOX) + else if (attr->name() == sandboxAttr) setSandboxFlags(parseSandboxAttribute(attr)); +#endif else HTMLFrameElementBase::parseMappedAttribute(attr); } @@ -136,7 +143,7 @@ bool HTMLIFrameElement::rendererIsNeeded(RenderStyle* style) RenderObject* HTMLIFrameElement::createRenderer(RenderArena* arena, RenderStyle*) { - return new (arena) RenderPartObject(this); + return new (arena) RenderIFrame(this); } void HTMLIFrameElement::insertedIntoDocument() diff --git a/WebCore/html/HTMLImageElement.cpp b/WebCore/html/HTMLImageElement.cpp index d3cea92..db66533 100644 --- a/WebCore/html/HTMLImageElement.cpp +++ b/WebCore/html/HTMLImageElement.cpp @@ -435,4 +435,10 @@ void HTMLImageElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) cons addSubresourceURL(urls, document()->completeURL(getAttribute(usemapAttr))); } +void HTMLImageElement::willMoveToNewOwnerDocument() +{ + m_imageLoader.elementWillMoveToNewOwnerDocument(); + HTMLElement::willMoveToNewOwnerDocument(); +} + } diff --git a/WebCore/html/HTMLImageElement.h b/WebCore/html/HTMLImageElement.h index d7df1dc..e9b813c 100644 --- a/WebCore/html/HTMLImageElement.h +++ b/WebCore/html/HTMLImageElement.h @@ -105,6 +105,9 @@ public: virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const; +protected: + virtual void willMoveToNewOwnerDocument(); + private: virtual void insertedIntoDocument(); virtual void removedFromDocument(); diff --git a/WebCore/html/HTMLInputElement.cpp b/WebCore/html/HTMLInputElement.cpp index c3f6703..60669ef 100644 --- a/WebCore/html/HTMLInputElement.cpp +++ b/WebCore/html/HTMLInputElement.cpp @@ -2,7 +2,7 @@ * Copyright (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 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * (C) 2006 Alexey Proskuryakov (ap@nypop.com) * Copyright (C) 2007 Samuel Weinig (sam@webkit.org) * @@ -60,6 +60,7 @@ #include "RenderText.h" #include "RenderTextControlSingleLine.h" #include "RenderTheme.h" +#include "StepRange.h" #include "StringHash.h" #include "TextEvent.h" #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS @@ -157,13 +158,14 @@ bool HTMLInputElement::autoComplete() const { if (m_autocomplete != Uninitialized) return m_autocomplete == On; - - // Assuming we're still in a Form, respect the Form's setting - if (HTMLFormElement* form = this->form()) - return form->autoComplete(); - - // The default is true - return true; + return HTMLTextFormControlElement::autoComplete(); +} + +static inline CheckedRadioButtons& checkedRadioButtons(const HTMLInputElement* element) +{ + if (HTMLFormElement* form = element->form()) + return form->checkedRadioButtons(); + return element->document()->checkedRadioButtons(); } bool HTMLInputElement::valueMissing() const @@ -190,7 +192,7 @@ bool HTMLInputElement::valueMissing() const case CHECKBOX: return !checked(); case RADIO: - return !document()->checkedRadioButtons().checkedButtonForGroup(name()); + return !checkedRadioButtons(this).checkedButtonForGroup(name()); case COLOR: return false; case BUTTON: @@ -270,7 +272,7 @@ bool HTMLInputElement::tooLong() const bool userEdited = !m_data.value().isNull(); if (!userEdited) return false; - return value().numGraphemeClusters() > static_cast<unsigned>(max); + return numGraphemeClusters(value()) > static_cast<unsigned>(max); } case BUTTON: case CHECKBOX: @@ -305,12 +307,13 @@ bool HTMLInputElement::rangeUnderflow() const case DATETIMELOCAL: case MONTH: case NUMBER: - case RANGE: case TIME: case WEEK: { double doubleValue = parseToDouble(value(), nan); return isfinite(doubleValue) && doubleValue < minimum(); } + case RANGE: // Guaranteed by sanitization. + ASSERT(parseToDouble(value(), nan) >= minimum()); case BUTTON: case CHECKBOX: case COLOR: @@ -341,12 +344,13 @@ bool HTMLInputElement::rangeOverflow() const case DATETIMELOCAL: case MONTH: case NUMBER: - case RANGE: case TIME: case WEEK: { double doubleValue = parseToDouble(value(), nan); - return isfinite(doubleValue) && doubleValue > maximum(); + return isfinite(doubleValue) && doubleValue > maximum(); } + case RANGE: // Guaranteed by sanitization. + ASSERT(parseToDouble(value(), nan) <= maximum()); case BUTTON: case CHECKBOX: case COLOR: @@ -499,7 +503,8 @@ bool HTMLInputElement::stepMismatch() const switch (inputType()) { case RANGE: // stepMismatch doesn't occur for RANGE. RenderSlider guarantees the - // value matches to step. + // value matches to step on user input, and sanitation takes care + // of the general case. return false; case NUMBER: { double doubleValue; @@ -681,14 +686,6 @@ void HTMLInputElement::stepDown(int n, ExceptionCode& ec) applyStep(-n, ec); } -static inline CheckedRadioButtons& checkedRadioButtons(const HTMLInputElement *element) -{ - if (HTMLFormElement* form = element->form()) - return form->checkedRadioButtons(); - - return element->document()->checkedRadioButtons(); -} - bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const { // If text fields can be focused, then they should always be keyboard focusable @@ -809,7 +806,6 @@ void HTMLInputElement::setInputType(const String& t) // type change, otherwise a JavaScript programmer would be able to set a text // field's value to something like /etc/passwd and then change it to a file field. if (inputType() != newType) { - bool oldWillValidate = willValidate(); if (newType == FILE && m_haveType) // Set the attribute back to the old value. // Useful in case we were called from inside parseMappedAttribute. @@ -828,6 +824,7 @@ void HTMLInputElement::setInputType(const String& t) bool wasPasswordField = inputType() == PASSWORD; bool didRespectHeightAndWidth = respectHeightAndWidthAttrs(); m_type = newType; + setNeedsWillValidateCheck(); bool willStoreValue = storesValueSeparateFromAttribute(); bool isPasswordField = inputType() == PASSWORD; bool willRespectHeightAndWidth = respectHeightAndWidthAttrs(); @@ -867,8 +864,6 @@ void HTMLInputElement::setInputType(const String& t) } setNeedsValidityCheck(); - if (oldWillValidate != willValidate()) - setNeedsWillValidateCheck(); InputElement::notifyFormStateChanged(this); } m_haveType = true; @@ -917,9 +912,6 @@ const AtomicString& HTMLInputElement::formControlType() const bool HTMLInputElement::saveFormControlState(String& result) const { - if (!autoComplete()) - return false; - switch (inputType()) { case BUTTON: case COLOR: @@ -941,9 +933,13 @@ bool HTMLInputElement::saveFormControlState(String& result) const case TEXT: case TIME: case URL: - case WEEK: - result = value(); + case WEEK: { + String currentValue = value(); + if (currentValue == defaultValue()) + return false; + result = currentValue; return true; + } case CHECKBOX: case RADIO: result = checked() ? "on" : "off"; @@ -1150,8 +1146,14 @@ void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr) || attr->name() == incrementalAttr) setNeedsStyleRecalc(); else if (attr->name() == minAttr - || attr->name() == maxAttr - || attr->name() == multipleAttr + || attr->name() == maxAttr) { + if (inputType() == RANGE) { + // Sanitize the value. + setValue(value()); + setNeedsStyleRecalc(); + } + setNeedsValidityCheck(); + } else if (attr->name() == multipleAttr || attr->name() == patternAttr || attr->name() == precisionAttr || attr->name() == stepAttr) @@ -1359,12 +1361,12 @@ bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart) // If no filename at all is entered, return successful but empty. // Null would be more logical, but Netscape posts an empty file. Argh. if (!numFiles) { - encoding.appendFile(name(), File::create("")); + encoding.appendBlob(name(), File::create("")); return true; } for (unsigned i = 0; i < numFiles; ++i) - encoding.appendFile(name(), m_fileList->item(i)); + encoding.appendBlob(name(), m_fileList->item(i)); return true; } } @@ -1447,8 +1449,8 @@ void HTMLInputElement::setChecked(bool nowChecked, bool sendChangeEvent) void HTMLInputElement::setIndeterminate(bool _indeterminate) { - // Only checkboxes honor indeterminate. - if (inputType() != CHECKBOX || indeterminate() == _indeterminate) + // Only checkboxes and radio buttons honor indeterminate. + if (!allowsIndeterminate() || indeterminate() == _indeterminate) return; m_indeterminate = _indeterminate; @@ -1490,10 +1492,16 @@ String HTMLInputElement::value() const String value = m_data.value(); if (value.isNull()) { value = sanitizeValue(getAttribute(valueAttr)); - - // If no attribute exists, then just use "on" or "" based off the checked() state of the control. - if (value.isNull() && (inputType() == CHECKBOX || inputType() == RADIO)) - return checked() ? "on" : ""; + + // If no attribute exists, extra handling may be necessary. + // For Checkbox Types just use "on" or "" based off the checked() state of the control. + // For a Range Input use the calculated default value. + if (value.isNull()) { + if (inputType() == CHECKBOX || inputType() == RADIO) + return checked() ? "on" : ""; + else if (inputType() == RANGE) + return serializeForNumberType(StepRange(this).defaultValue()); + } } return value; @@ -1575,18 +1583,15 @@ void HTMLInputElement::setValue(const String& value, bool sendChangeEvent) m_fileList->clear(); else { m_data.setValue(sanitizeValue(value)); - if (isTextField()) { + if (isTextField()) updatePlaceholderVisibility(false); - if (inDocument()) - document()->updateStyleIfNeeded(); - } } - if (renderer()) - renderer()->updateFromElement(); setNeedsStyleRecalc(); } else setAttribute(valueAttr, sanitizeValue(value)); + setNeedsValidityCheck(); + if (isTextField()) { unsigned max = m_data.value().length(); #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS @@ -1606,7 +1611,6 @@ void HTMLInputElement::setValue(const String& value, bool sendChangeEvent) dispatchFormControlChangeEvent(); InputElement::notifyFormStateChanged(this); - setNeedsValidityCheck(); } double HTMLInputElement::parseToDouble(const String& src, double defaultValue) const @@ -1989,6 +1993,16 @@ bool HTMLInputElement::storesValueSeparateFromAttribute() const return false; } +struct EventHandlingState { + RefPtr<HTMLInputElement> m_currRadio; + bool m_indeterminate; + bool m_checked; + + EventHandlingState(bool indeterminate, bool checked) + : m_indeterminate(indeterminate) + , m_checked(checked) { } +}; + void* HTMLInputElement::preDispatchEventHandler(Event *evt) { // preventDefault or "return false" are used to reverse the automatic checking/selection we do here. @@ -1996,17 +2010,14 @@ void* HTMLInputElement::preDispatchEventHandler(Event *evt) void* result = 0; if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent() && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) { + + EventHandlingState* state = new EventHandlingState(indeterminate(), checked()); + if (inputType() == CHECKBOX) { - // As a way to store the state, we return 0 if we were unchecked, 1 if we were checked, and 2 for - // indeterminate. - if (indeterminate()) { - result = (void*)0x2; + if (indeterminate()) setIndeterminate(false); - } else { - if (checked()) - result = (void*)0x1; + else setChecked(!checked(), true); - } } else { // For radio buttons, store the current selected radio object. // We really want radio groups to end up in sane states, i.e., to have something checked. @@ -2016,11 +2027,13 @@ void* HTMLInputElement::preDispatchEventHandler(Event *evt) if (currRadio) { // We have a radio button selected that is not us. Cache it in our result field and ref it so // that it can't be destroyed. - currRadio->ref(); - result = currRadio; + state->m_currRadio = currRadio; } + if (indeterminate()) + setIndeterminate(false); setChecked(true, true); } + result = state; } return result; } @@ -2029,28 +2042,30 @@ void HTMLInputElement::postDispatchEventHandler(Event *evt, void* data) { if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent() && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) { - if (inputType() == CHECKBOX) { - // Reverse the checking we did in preDispatch. - if (evt->defaultPrevented() || evt->defaultHandled()) { - if (data == (void*)0x2) - setIndeterminate(true); - else - setChecked(data); - } - } else if (data) { - HTMLInputElement* input = static_cast<HTMLInputElement*>(data); - if (evt->defaultPrevented() || evt->defaultHandled()) { - // Restore the original selected radio button if possible. - // Make sure it is still a radio button and only do the restoration if it still - // belongs to our group. - - if (input->form() == form() && input->inputType() == RADIO && input->name() == name()) { - // Ok, the old radio button is still in our form and in our group and is still a - // radio button, so it's safe to restore selection to it. - input->setChecked(true); + + if (EventHandlingState* state = reinterpret_cast<EventHandlingState*>(data)) { + if (inputType() == CHECKBOX) { + // Reverse the checking we did in preDispatch. + if (evt->defaultPrevented() || evt->defaultHandled()) { + setIndeterminate(state->m_indeterminate); + setChecked(state->m_checked); + } + } else { + HTMLInputElement* input = state->m_currRadio.get(); + if (evt->defaultPrevented() || evt->defaultHandled()) { + // Restore the original selected radio button if possible. + // Make sure it is still a radio button and only do the restoration if it still + // belongs to our group. + + if (input && input->form() == form() && input->inputType() == RADIO && input->name() == name()) { + // Ok, the old radio button is still in our form and in our group and is still a + // radio button, so it's safe to restore selection to it. + input->setChecked(true); + } + setIndeterminate(state->m_indeterminate); } } - input->deref(); + delete state; } // Left clicks on radio buttons and check boxes already performed default actions in preDispatchEventHandler(). @@ -2505,6 +2520,13 @@ String HTMLInputElement::sanitizeValue(const String& proposedValue) const { if (isTextField()) return InputElement::sanitizeValue(this, proposedValue); + + // If the proposedValue is null than this is a reset scenario and we + // want the range input's value attribute to take priority over the + // calculated default (middle) value. + if (inputType() == RANGE && !proposedValue.isNull()) + return serializeForNumberType(StepRange(this).clampValue(proposedValue)); + return proposedValue; } @@ -2592,6 +2614,9 @@ void HTMLInputElement::documentDidBecomeActive() void HTMLInputElement::willMoveToNewOwnerDocument() { + if (m_imageLoader) + m_imageLoader->elementWillMoveToNewOwnerDocument(); + // Always unregister for cache callbacks when leaving a document, even if we would otherwise like to be registered if (needsActivationCallback()) document()->unregisterForDocumentActivationCallbacks(this); @@ -2615,11 +2640,10 @@ void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) cons addSubresourceURL(urls, src()); } -bool HTMLInputElement::willValidate() const +bool HTMLInputElement::recalcWillValidate() const { - // FIXME: This shall check for new WF2 input types too - return HTMLFormControlElementWithState::willValidate() && inputType() != HIDDEN && - inputType() != BUTTON && inputType() != RESET; + return HTMLFormControlElementWithState::recalcWillValidate() + && inputType() != HIDDEN && inputType() != BUTTON && inputType() != RESET; } String HTMLInputElement::serializeForNumberType(double number) diff --git a/WebCore/html/HTMLInputElement.h b/WebCore/html/HTMLInputElement.h index 40930ac..c3b0a73 100644 --- a/WebCore/html/HTMLInputElement.h +++ b/WebCore/html/HTMLInputElement.h @@ -131,8 +131,12 @@ public: bool checked() const { return m_checked; } void setChecked(bool, bool sendChangeEvent = false); + + // 'indeterminate' is a state independent of the checked state that causes the control to draw in a way that hides the actual state. + bool allowsIndeterminate() const { return inputType() == CHECKBOX || inputType() == RADIO; } bool indeterminate() const { return m_indeterminate; } void setIndeterminate(bool); + virtual int size() const; virtual const AtomicString& formControlType() const; void setType(const String&); @@ -257,8 +261,6 @@ public: virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const; - virtual bool willValidate() const; - // Converts the specified string to a floating number. // If the conversion fails, the return value is false. Take care that leading or trailing unnecessary characters make failures. This returns false for an empty string input. // The double* parameter may be 0. @@ -291,6 +293,7 @@ private: virtual bool isOptionalFormControl() const { return !isRequiredFormControl(); } virtual bool isRequiredFormControl() const; + virtual bool recalcWillValidate() const; PassRefPtr<HTMLFormElement> createTemporaryFormForIsIndex(); // Helper for getAllowedValueStep(); diff --git a/WebCore/html/HTMLLabelElement.cpp b/WebCore/html/HTMLLabelElement.cpp index 06b3b2f..645017d 100644 --- a/WebCore/html/HTMLLabelElement.cpp +++ b/WebCore/html/HTMLLabelElement.cpp @@ -139,6 +139,8 @@ void HTMLLabelElement::accessKeyAction(bool sendToAnyElement) { if (HTMLElement* element = correspondingControl()) element->accessKeyAction(sendToAnyElement); + else + HTMLElement::accessKeyAction(sendToAnyElement); } String HTMLLabelElement::accessKey() const diff --git a/WebCore/html/HTMLLinkElement.cpp b/WebCore/html/HTMLLinkElement.cpp index daa1702..7942e67 100644 --- a/WebCore/html/HTMLLinkElement.cpp +++ b/WebCore/html/HTMLLinkElement.cpp @@ -26,7 +26,6 @@ #include "CSSHelper.h" #include "CachedCSSStyleSheet.h" -#include "DNS.h" #include "DocLoader.h" #include "Document.h" #include "Frame.h" @@ -38,6 +37,7 @@ #include "MediaList.h" #include "MediaQueryEvaluator.h" #include "Page.h" +#include "ResourceHandle.h" #include "ScriptEventListener.h" #include "Settings.h" #include <wtf/StdLibExtras.h> @@ -201,6 +201,7 @@ void HTMLLinkElement::process() if (m_rel.m_isIcon && m_url.isValid() && !m_url.isEmpty()) document()->setIconURL(m_url.string(), type); +<<<<<<< HEAD #ifdef ANDROID_APPLE_TOUCH_ICON if ((m_rel.m_isTouchIcon || m_rel.m_isPrecomposedTouchIcon) && m_url.isValid() && !m_url.isEmpty()) @@ -211,6 +212,10 @@ void HTMLLinkElement::process() if (m_rel.m_isDNSPrefetch && m_url.isValid() && !m_url.isEmpty()) prefetchDNS(m_url.host()); +======= + if (m_isDNSPrefetch && m_url.isValid() && !m_url.isEmpty()) + ResourceHandle::prepareForURL(m_url); +>>>>>>> webkit.org at r58033 #if ENABLE(LINK_PREFETCH) if (m_rel.m_isLinkPrefetch && m_url.isValid()) { @@ -231,7 +236,7 @@ void HTMLLinkElement::process() String charset = getAttribute(charsetAttr); if (charset.isEmpty() && document()->frame()) - charset = document()->frame()->loader()->encoding(); + charset = document()->frame()->loader()->writer()->encoding(); if (m_cachedSheet) { if (m_loading) diff --git a/WebCore/html/HTMLMapElement.cpp b/WebCore/html/HTMLMapElement.cpp index 9617afc..10a05d6 100644 --- a/WebCore/html/HTMLMapElement.cpp +++ b/WebCore/html/HTMLMapElement.cpp @@ -79,7 +79,7 @@ bool HTMLMapElement::mapMouseEvent(int x, int y, const IntSize& size, HitTestRes HTMLImageElement* HTMLMapElement::imageElement() const { - RefPtr<HTMLCollection> coll = renderer()->document()->images(); + RefPtr<HTMLCollection> coll = document()->images(); for (Node* curr = coll->firstItem(); curr; curr = coll->nextItem()) { if (!curr->hasTagName(imgTag)) continue; diff --git a/WebCore/html/HTMLMediaElement.cpp b/WebCore/html/HTMLMediaElement.cpp index e5594ae..20fa7f8 100644 --- a/WebCore/html/HTMLMediaElement.cpp +++ b/WebCore/html/HTMLMediaElement.cpp @@ -70,7 +70,7 @@ #endif #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) -#include "RenderPartObject.h" +#include "RenderEmbeddedObject.h" #include "Widget.h" #endif @@ -101,9 +101,14 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* doc) , m_loadState(WaitingForSource) , m_currentSourceNode(0) , m_player(0) +#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) + , m_proxyWidget(0) +#endif , m_restrictions(NoRestrictions) + , m_preload(MediaPlayer::Auto) , m_playing(false) , m_processingMediaPlayerCallback(0) + , m_isWaitingUntilMediaCanStart(false) , m_processingLoad(false) , m_delayingTheLoadEvent(false) , m_haveFiredLoadedData(false) @@ -128,6 +133,11 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* doc) HTMLMediaElement::~HTMLMediaElement() { + if (m_isWaitingUntilMediaCanStart) { + if (Page* page = document()->page()) + page->removeMediaCanStartListener(this); + } + document()->unregisterForDocumentActivationCallbacks(this); document()->unregisterForMediaVolumeCallbacks(this); } @@ -158,10 +168,10 @@ void HTMLMediaElement::attributeChanged(Attribute* attr, bool preserveDecls) const QualifiedName& attrName = attr->name(); if (attrName == srcAttr) { - // don't have a src or any <source> children, trigger load - if (inDocument() && m_loadState == WaitingForSource) + // Trigger a reload, as long as the 'src' attribute is present. + if (!getAttribute(srcAttr).isEmpty()) scheduleLoad(); - } + } #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO) else if (attrName == controlsAttr) { if (!isVideo() && attached() && (controls() != (renderer() != 0))) { @@ -178,9 +188,23 @@ void HTMLMediaElement::parseMappedAttribute(MappedAttribute* attr) { const QualifiedName& attrName = attr->name(); - if (attrName == autobufferAttr) { - if (m_player) - m_player->setAutobuffer(!attr->isNull()); + if (attrName == preloadAttr) { + String value = attr->value(); + + if (equalIgnoringCase(value, "none")) + m_preload = MediaPlayer::None; + else if (equalIgnoringCase(value, "metadata")) + m_preload = MediaPlayer::MetaData; + else { + // The spec does not define an "invalid value default" but "auto" is suggested as the + // "missing value default", so use it for everything except "none" and "metadata" + m_preload = MediaPlayer::Auto; + } + + // The attribute must be ignored if the autoplay attribute is present + if (!autoplay() && m_player) + m_player->setPreload(m_preload); + } else if (attrName == onabortAttr) setAttributeEventListener(eventNames().abortEvent, createAttributeEventListener(this, attr)); else if (attrName == onbeforeloadAttr) @@ -254,7 +278,11 @@ bool HTMLMediaElement::rendererIsNeeded(RenderStyle* style) RenderObject* HTMLMediaElement::createRenderer(RenderArena* arena, RenderStyle*) { #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) - return new (arena) RenderEmbeddedObject(this); + // Setup the renderer if we already have a proxy widget. + RenderEmbeddedObject* mediaRenderer = new (arena) RenderEmbeddedObject(this); + if (m_proxyWidget) + mediaRenderer->setWidget(m_proxyWidget); + return mediaRenderer; #else return new (arena) RenderMedia(this); #endif @@ -300,6 +328,10 @@ void HTMLMediaElement::recalcStyle(StyleChange change) void HTMLMediaElement::scheduleLoad() { +#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) + createMediaPlayerProxy(); +#endif + if (m_loadTimer.isActive()) return; prepareForLoad(); @@ -439,39 +471,30 @@ void HTMLMediaElement::prepareForLoad() m_sentStalledEvent = false; m_haveFiredLoadedData = false; - // 2 - Abort any already-running instance of the resource selection algorithm for this element. + // 1 - Abort any already-running instance of the resource selection algorithm for this element. m_currentSourceNode = 0; - // 3 - If there are any tasks from the media element's media element event task source in + // 2 - If there are any tasks from the media element's media element event task source in // one of the task queues, then remove those tasks. cancelPendingEventsAndCallbacks(); -} - -void HTMLMediaElement::loadInternal() -{ - // If the load() method for this element is already being invoked, then abort these steps. - if (m_processingLoad) - return; - m_processingLoad = true; - - // Steps 1 and 2 were done in prepareForLoad() // 3 - If the media element's networkState is set to NETWORK_LOADING or NETWORK_IDLE, queue // a task to fire a simple event named abort at the media element. if (m_networkState == NETWORK_LOADING || m_networkState == NETWORK_IDLE) scheduleEvent(eventNames().abortEvent); - // 4 +#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO) + m_player = MediaPlayer::create(this); +#else + createMediaPlayerProxy(); +#endif + + // 4 - If the media element's networkState is not set to NETWORK_EMPTY, then run these substeps if (m_networkState != NETWORK_EMPTY) { m_networkState = NETWORK_EMPTY; m_readyState = HAVE_NOTHING; m_paused = true; m_seeking = false; - if (m_player) { - m_player->pause(); - m_playing = false; - m_player->seek(0); - } scheduleEvent(eventNames().emptiedEvent); } @@ -486,6 +509,22 @@ void HTMLMediaElement::loadInternal() m_lastSeekTime = 0; m_closedCaptionsVisible = false; +} + +void HTMLMediaElement::loadInternal() +{ + // If we can't start a load right away, start it later. + Page* page = document()->page(); + if (page && !page->canStartMedia()) { + if (m_isWaitingUntilMediaCanStart) + return; + page->addMediaCanStartListener(this); + m_isWaitingUntilMediaCanStart = true; + return; + } + + // Steps 1 - 6 were done in prepareForLoad + // 7 - Invoke the media element's resource selection algorithm. selectMediaResource(); m_processingLoad = false; @@ -552,6 +591,11 @@ void HTMLMediaElement::loadNextSourceChild() return; } +#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO) + // Recreate the media player for the new url + m_player = MediaPlayer::create(this); +#endif + m_loadState = LoadingFromSourceElement; loadResource(mediaURL, contentType); } @@ -579,14 +623,8 @@ void HTMLMediaElement::loadResource(const KURL& initialURL, ContentType& content if (m_sendProgressEvents) startProgressEventTimer(); -#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO) - m_player = MediaPlayer::create(this); -#else - if (!m_player) - m_player = MediaPlayer::create(this); -#endif - - m_player->setAutobuffer(autobuffer()); + if (!autoplay()) + m_player->setPreload(m_preload); m_player->setPreservesPitch(m_webkitPreservesPitch); updateVolume(); @@ -599,7 +637,7 @@ void HTMLMediaElement::loadResource(const KURL& initialURL, ContentType& content #endif if (isVideo() && m_player->canLoadPoster()) { - KURL posterUrl = static_cast<HTMLVideoElement*>(this)->poster(); + KURL posterUrl = poster(); if (!posterUrl.isEmpty()) m_player->setPoster(posterUrl); } @@ -712,6 +750,16 @@ void HTMLMediaElement::cancelPendingEventsAndCallbacks() } } +Document* HTMLMediaElement::mediaPlayerOwningDocument() +{ + Document* d = document(); + + if (!d) + d = ownerDocument(); + + return d; +} + void HTMLMediaElement::mediaPlayerNetworkStateChanged(MediaPlayer*) { beginProcessingMediaPlayerCallback(); @@ -755,7 +803,7 @@ void HTMLMediaElement::setNetworkState(MediaPlayer::NetworkState state) if (state == MediaPlayer::Idle) { if (m_networkState > NETWORK_IDLE) { - stopPeriodicTimers(); + m_progressEventTimer.stop(); scheduleEvent(eventNames().suspendEvent); } m_networkState = NETWORK_IDLE; @@ -1042,7 +1090,7 @@ float HTMLMediaElement::startTime() const float HTMLMediaElement::duration() const { - if (m_readyState >= HAVE_METADATA) + if (m_player && m_readyState >= HAVE_METADATA) return m_player->duration(); return numeric_limits<float>::quiet_NaN(); @@ -1114,14 +1162,27 @@ void HTMLMediaElement::setAutoplay(bool b) setBooleanAttribute(autoplayAttr, b); } -bool HTMLMediaElement::autobuffer() const +String HTMLMediaElement::preload() const { - return hasAttribute(autobufferAttr); + switch (m_preload) { + case MediaPlayer::None: + return "none"; + break; + case MediaPlayer::MetaData: + return "metadata"; + break; + case MediaPlayer::Auto: + return "auto"; + break; + } + + ASSERT_NOT_REACHED(); + return String(); } -void HTMLMediaElement::setAutobuffer(bool b) +void HTMLMediaElement::setPreload(const String& preload) { - setBooleanAttribute(autobufferAttr, b); + setAttribute(preloadAttr, preload); } void HTMLMediaElement::play(bool isUserGesture) @@ -1200,7 +1261,7 @@ bool HTMLMediaElement::controls() const Frame* frame = document()->frame(); // always show controls when scripting is disabled - if (frame && !frame->script()->canExecuteScripts()) + if (frame && !frame->script()->canExecuteScripts(NotAboutToExecuteScript)) return true; return hasAttribute(controlsAttr); @@ -1241,7 +1302,7 @@ void HTMLMediaElement::setMuted(bool muted) m_muted = muted; // Avoid recursion when the player reports volume changes. if (!processingMediaPlayerCallback()) { - if (m_player && m_player->supportsMuting()) { + if (m_player) { m_player->setMuted(m_muted); if (renderer()) renderer()->updateFromElement(); @@ -1645,7 +1706,8 @@ void HTMLMediaElement::updateVolume() Page* page = document()->page(); float volumeMultiplier = page ? page->mediaVolume() : 1; - m_player->setVolume(m_muted ? 0 : m_volume * volumeMultiplier); + m_player->setMuted(m_muted); + m_player->setVolume(m_volume * volumeMultiplier); } if (renderer()) @@ -1735,6 +1797,9 @@ void HTMLMediaElement::userCancelledLoad() // 7 - Abort the overall resource selection algorithm. m_currentSourceNode = 0; + + // Reset m_readyState since m_player is gone. + m_readyState = HAVE_NOTHING; } void HTMLMediaElement::documentWillBecomeInactive() @@ -1778,12 +1843,11 @@ void HTMLMediaElement::mediaVolumeDidChange() updateVolume(); } -const IntRect HTMLMediaElement::screenRect() +IntRect HTMLMediaElement::screenRect() { - IntRect elementRect; - if (renderer()) - elementRect = renderer()->view()->frameView()->contentsToScreen(renderer()->absoluteBoundingBoxRect()); - return elementRect; + if (!renderer()) + return IntRect(); + return renderer()->view()->frameView()->contentsToScreen(renderer()->absoluteBoundingBoxRect()); } void HTMLMediaElement::defaultEventHandler(Event* event) @@ -1816,6 +1880,12 @@ bool HTMLMediaElement::processingUserGesture() const #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) +void HTMLMediaElement::ensureMediaPlayer() +{ + if (!m_player) + m_player = MediaPlayer::create(this); +} + void HTMLMediaElement::deliverNotification(MediaPlayerProxyNotificationType notification) { if (notification == MediaPlayerNotificationPlayPauseButtonPressed) { @@ -1829,34 +1899,76 @@ void HTMLMediaElement::deliverNotification(MediaPlayerProxyNotificationType noti void HTMLMediaElement::setMediaPlayerProxy(WebMediaPlayerProxy* proxy) { - if (m_player) - m_player->setMediaPlayerProxy(proxy); + ensureMediaPlayer(); + m_player->setMediaPlayerProxy(proxy); } -String HTMLMediaElement::initialURL() +void HTMLMediaElement::getPluginProxyParams(KURL& url, Vector<String>& names, Vector<String>& values) { - KURL initialSrc = document()->completeURL(getAttribute(srcAttr)); - - if (!initialSrc.isValid()) - initialSrc = selectNextSourceChild(0, DoNothing); + Frame* frame = document()->frame(); + FrameLoader* loader = frame ? frame->loader() : 0; - m_currentSrc = initialSrc.string(); + if (isVideo()) { + String poster = poster(); + if (!poster.isEmpty() && loader) { + KURL posterURL = loader->completeURL(poster); + if (posterURL.isValid() && loader->willLoadMediaElementURL(posterURL)) { + names.append("_media_element_poster_"); + values.append(posterURL.string()); + } + } + } + + if (controls()) { + names.append("_media_element_controls_"); + values.append("true"); + } - return initialSrc; + url = src(); + if (!url.isValid() || !isSafeToLoadURL(url, Complain)) + url = selectNextSourceChild(0, DoNothing); + + m_currentSrc = url.string(); + if (url.isValid() && loader && loader->willLoadMediaElementURL(url)) { + names.append("_media_element_src_"); + values.append(m_currentSrc); + } } void HTMLMediaElement::finishParsingChildren() { HTMLElement::finishParsingChildren(); - if (!m_player) - m_player = MediaPlayer::create(this); - document()->updateStyleIfNeeded(); - if (m_needWidgetUpdate && renderer()) - toRenderEmbeddedObject(renderer())->updateWidget(true); + createMediaPlayerProxy(); } -#endif +void HTMLMediaElement::createMediaPlayerProxy() +{ + ensureMediaPlayer(); + + if (!inDocument() && m_proxyWidget) + return; + if (inDocument() && !m_needWidgetUpdate) + return; + + Frame* frame = document()->frame(); + FrameLoader* loader = frame ? frame->loader() : 0; + if (!loader) + return; + + KURL url; + Vector<String> paramNames; + Vector<String> paramValues; + + getPluginProxyParams(url, paramNames, paramValues); + + // Hang onto the proxy widget so it won't be destroyed if the plug-in is set to + // display:none + m_proxyWidget = loader->loadMediaPlayerProxyPlugin(this, url, paramNames, paramValues); + if (m_proxyWidget) + m_needWidgetUpdate = false; +} +#endif // ENABLE(PLUGIN_PROXY_FOR_VIDEO) void HTMLMediaElement::enterFullscreen() { @@ -1927,6 +2039,13 @@ bool HTMLMediaElement::webkitHasClosedCaptions() const return hasClosedCaptions(); } +void HTMLMediaElement::mediaCanStart() +{ + ASSERT(m_isWaitingUntilMediaCanStart); + m_isWaitingUntilMediaCanStart = false; + loadInternal(); +} + } #endif diff --git a/WebCore/html/HTMLMediaElement.h b/WebCore/html/HTMLMediaElement.h index 07801da..83e1f2c 100644 --- a/WebCore/html/HTMLMediaElement.h +++ b/WebCore/html/HTMLMediaElement.h @@ -29,8 +29,8 @@ #if ENABLE(VIDEO) #include "HTMLElement.h" +#include "MediaCanStartListener.h" #include "MediaPlayer.h" -#include "Timer.h" #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) #include "MediaPlayerProxy.h" @@ -43,23 +43,16 @@ class HTMLSourceElement; class MediaError; class KURL; class TimeRanges; +#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) +class Widget; +#endif -class HTMLMediaElement : public HTMLElement, public MediaPlayerClient { -public: - virtual ~HTMLMediaElement(); - - bool checkDTD(const Node* newChild); - - void attributeChanged(Attribute*, bool preserveDecls); - void parseMappedAttribute(MappedAttribute *); +// FIXME: The inheritance from MediaPlayerClient here should be private inheritance. +// But it can't be until the Chromium WebMediaPlayerClientImpl class is fixed so it +// no longer depends on typecasting a MediaPlayerClient to an HTMLMediaElement. - virtual bool rendererIsNeeded(RenderStyle*); - virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); - virtual void insertedIntoDocument(); - virtual void removedFromDocument(); - virtual void attach(); - virtual void recalcStyle(StyleChange); - +class HTMLMediaElement : public HTMLElement, public MediaPlayerClient, private MediaCanStartListener { +public: MediaPlayer* player() const { return m_player.get(); } virtual bool isVideo() const = 0; @@ -71,6 +64,8 @@ public: // Eventually overloaded in HTMLVideoElement virtual bool supportsFullscreen() const { return false; }; + virtual const KURL poster() const { return KURL(); } + virtual bool supportsSave() const; PlatformMedia platformMedia() const; @@ -80,11 +75,6 @@ public: void scheduleLoad(); - virtual void defaultEventHandler(Event*); - - // Pauses playback without changing any states or generating events - void setPausedInternal(bool); - MediaPlayer::MovieLoadType movieLoadType() const; bool inActiveDocument() const { return m_inActiveDocument; } @@ -100,8 +90,9 @@ public: enum NetworkState { NETWORK_EMPTY, NETWORK_IDLE, NETWORK_LOADING, NETWORK_LOADED, NETWORK_NO_SOURCE }; NetworkState networkState() const; - bool autobuffer() const; - void setAutobuffer(bool); + + String preload() const; + void setPreload(const String&); PassRefPtr<TimeRanges> buffered() const; void load(bool isUserGesture, ExceptionCode&); @@ -150,22 +141,25 @@ public: void beginScrubbing(); void endScrubbing(); - const IntRect screenRect(); + IntRect screenRect(); bool canPlay() const; float percentLoaded() const; #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) + void allocateMediaPlayerIfNecessary(); void setNeedWidgetUpdate(bool needWidgetUpdate) { m_needWidgetUpdate = needWidgetUpdate; } void deliverNotification(MediaPlayerProxyNotificationType notification); void setMediaPlayerProxy(WebMediaPlayerProxy* proxy); - String initialURL(); + void getPluginProxyParams(KURL& url, Vector<String>& names, Vector<String>& values); virtual void finishParsingChildren(); + void createMediaPlayerProxy(); #endif bool hasSingleSecurityOrigin() const { return !m_player || m_player->hasSingleSecurityOrigin(); } + bool isFullscreen() const { return m_isFullscreen; } void enterFullscreen(); void exitFullscreen(); @@ -177,7 +171,25 @@ public: protected: HTMLMediaElement(const QualifiedName&, Document*); + virtual ~HTMLMediaElement(); + virtual void parseMappedAttribute(MappedAttribute*); + virtual void attach(); + + virtual void willMoveToNewOwnerDocument(); + virtual void didMoveToNewOwnerDocument(); + +private: + virtual bool checkDTD(const Node* newChild); + virtual void attributeChanged(Attribute*, bool preserveDecls); + virtual bool rendererIsNeeded(RenderStyle*); + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + virtual void insertedIntoDocument(); + virtual void removedFromDocument(); + virtual void recalcStyle(StyleChange); + + virtual void defaultEventHandler(Event*); + float getTimeOffsetAttribute(const QualifiedName&, float valueOnError) const; void setTimeOffsetAttribute(const QualifiedName&, float value); @@ -189,10 +201,7 @@ protected: void setReadyState(MediaPlayer::ReadyState); void setNetworkState(MediaPlayer::NetworkState); - virtual void willMoveToNewOwnerDocument(); - virtual void didMoveToNewOwnerDocument(); - -private: // MediaPlayerClient + virtual Document* mediaPlayerOwningDocument(); virtual void mediaPlayerNetworkStateChanged(MediaPlayer*); virtual void mediaPlayerReadyStateChanged(MediaPlayer*); virtual void mediaPlayerTimeChanged(MediaPlayer*); @@ -208,7 +217,6 @@ private: // MediaPlayerClient virtual void mediaPlayerRenderingModeChanged(MediaPlayer*); #endif -private: void loadTimerFired(Timer<HTMLMediaElement>*); void asyncEventTimerFired(Timer<HTMLMediaElement>*); void progressEventTimerFired(Timer<HTMLMediaElement>*); @@ -263,15 +271,19 @@ private: float minTimeSeekable() const; float maxTimeSeekable() const; - // Restrictions to change default behaviors. This is a effectively a compile time choice at the moment - // because there are no accessor methods. + // Pauses playback without changing any states or generating events + void setPausedInternal(bool); + + virtual void mediaCanStart(); + + // Restrictions to change default behaviors. This is effectively a compile time choice at the moment + // because there are no accessor functions. enum BehaviorRestrictions { NoRestrictions = 0, RequireUserGestureForLoadRestriction = 1 << 0, RequireUserGestureForRateChangeRestriction = 1 << 1, }; -protected: Timer<HTMLMediaElement> m_loadTimer; Timer<HTMLMediaElement> m_asyncEventTimer; Timer<HTMLMediaElement> m_progressEventTimer; @@ -303,18 +315,25 @@ protected: // loading state enum LoadState { WaitingForSource, LoadingFromSrcAttr, LoadingFromSourceElement }; LoadState m_loadState; - HTMLSourceElement *m_currentSourceNode; + HTMLSourceElement* m_currentSourceNode; OwnPtr<MediaPlayer> m_player; +#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) + RefPtr<Widget> m_proxyWidget; +#endif BehaviorRestrictions m_restrictions; + + MediaPlayer::Preload m_preload; bool m_playing; - // counter incremented while processing a callback from the media player, so we can avoid - // calling the media engine recursively + // Counter incremented while processing a callback from the media player, so we can avoid + // calling the media engine recursively. int m_processingMediaPlayerCallback; + bool m_isWaitingUntilMediaCanStart; + bool m_processingLoad : 1; bool m_delayingTheLoadEvent : 1; bool m_haveFiredLoadedData : 1; diff --git a/WebCore/html/HTMLMediaElement.idl b/WebCore/html/HTMLMediaElement.idl index 46a2b86..5cd3293 100644 --- a/WebCore/html/HTMLMediaElement.idl +++ b/WebCore/html/HTMLMediaElement.idl @@ -39,7 +39,7 @@ interface [Conditional=VIDEO] HTMLMediaElement : HTMLElement { const unsigned short NETWORK_LOADED = 3; const unsigned short NETWORK_NO_SOURCE = 4; readonly attribute unsigned short networkState; - attribute boolean autobuffer; + attribute DOMString preload; readonly attribute TimeRanges buffered; [NeedsUserGestureCheck] void load() diff --git a/WebCore/html/HTMLMetaElement.cpp b/WebCore/html/HTMLMetaElement.cpp index f90ad0e..35fd299 100644 --- a/WebCore/html/HTMLMetaElement.cpp +++ b/WebCore/html/HTMLMetaElement.cpp @@ -68,6 +68,7 @@ void HTMLMetaElement::insertedIntoDocument() void HTMLMetaElement::process() { +<<<<<<< HEAD #ifdef ANDROID_META_SUPPORT if (!inDocument() || m_content.isNull()) return; @@ -92,9 +93,17 @@ void HTMLMetaElement::process() android::WebViewCore::getWebViewCore(view)->updateViewport(); } #endif +======= + if (!inDocument() || m_content.isNull()) + return; + + if (equalIgnoringCase(name(), "viewport")) + document()->processViewport(m_content); + +>>>>>>> webkit.org at r58033 // Get the document to process the tag, but only if we're actually part of DOM tree (changing a meta tag while // it's not in the tree shouldn't have any effect on the document) - if (inDocument() && !m_equiv.isNull() && !m_content.isNull()) + if (!m_equiv.isNull()) document()->processHttpEquiv(m_equiv, m_content); } diff --git a/WebCore/html/HTMLObjectElement.idl b/WebCore/html/HTMLObjectElement.idl index 8d975ba..be91dc4 100644 --- a/WebCore/html/HTMLObjectElement.idl +++ b/WebCore/html/HTMLObjectElement.idl @@ -23,8 +23,7 @@ module html { interface [ DelegatingPutFunction, DelegatingGetOwnPropertySlot, - CustomCall, - HasOverridingNameGetter + CustomCall ] HTMLObjectElement : HTMLElement { readonly attribute HTMLFormElement form; attribute [ConvertNullToNullString, Reflect] DOMString code; diff --git a/WebCore/html/HTMLParser.cpp b/WebCore/html/HTMLParser.cpp index 644f63e..c5839a8 100644 --- a/WebCore/html/HTMLParser.cpp +++ b/WebCore/html/HTMLParser.cpp @@ -400,7 +400,7 @@ bool HTMLParser::insertNode(Node* n, bool flat) n->finishParsingChildren(); } - if (localName == htmlTag && m_document->frame()) + if (localName == htmlTag && m_document->frame() && !m_isParsingFragment) m_document->frame()->loader()->dispatchDocumentElementAvailable(); return true; @@ -446,7 +446,7 @@ bool HTMLParser::handleError(Node* n, bool flat, const AtomicString& localName, } } else if (h->hasLocalName(htmlTag)) { if (!m_current->isDocumentNode() ) { - if (m_document->documentElement() && m_document->documentElement()->hasTagName(htmlTag)) { + if (m_document->documentElement() && m_document->documentElement()->hasTagName(htmlTag) && !m_isParsingFragment) { reportError(RedundantHTMLBodyError, &localName); // we have another <HTML> element.... apply attributes to existing one // make sure we don't overwrite already existing attributes @@ -489,7 +489,7 @@ bool HTMLParser::handleError(Node* n, bool flat, const AtomicString& localName, return false; } } else if (h->hasLocalName(bodyTag)) { - if (m_inBody && m_document->body()) { + if (m_inBody && m_document->body() && !m_isParsingFragment) { // we have another <BODY> element.... apply attributes to existing one // make sure we don't overwrite already existing attributes // some sites use <body bgcolor=rightcolor>...<body bgcolor=wrongcolor> @@ -503,8 +503,7 @@ bool HTMLParser::handleError(Node* n, bool flat, const AtomicString& localName, existingBody->setAttribute(it->name(), it->value()); } return false; - } - else if (!m_current->isDocumentNode()) + } else if (!m_current->isDocumentNode()) return false; } else if (h->hasLocalName(areaTag)) { if (m_currentMapElement) { @@ -551,7 +550,7 @@ bool HTMLParser::handleError(Node* n, bool flat, const AtomicString& localName, if (!m_haveFrameSet) { // Ensure that head exists. // But not for older versions of Mail, where the implicit <head> isn't expected - <rdar://problem/6863795> - if (shouldCreateImplicitHead(m_document)) + if (!m_isParsingFragment && shouldCreateImplicitHead(m_document)) createHead(); popBlock(headTag); @@ -758,7 +757,7 @@ bool HTMLParser::framesetCreateErrorCheck(Token*, RefPtr<Node>&) // we can't implement that behaviour now because it could cause too many // regressions and the headaches are not worth the work as long as there is // no site actually relying on that detail (Dirk) - if (m_document->body()) + if (m_document->body() && !m_isParsingFragment) m_document->body()->setAttribute(styleAttr, "display:none"); m_inBody = false; } @@ -876,8 +875,8 @@ bool HTMLParser::noframesCreateErrorCheck(Token*, RefPtr<Node>&) bool HTMLParser::noscriptCreateErrorCheck(Token*, RefPtr<Node>&) { if (!m_isParsingFragment) { - Settings* settings = m_document->settings(); - if (settings && settings->isJavaScriptEnabled()) + Frame* frame = m_document->frame(); + if (frame && frame->script()->canExecuteScripts(NotAboutToExecuteScript)) setSkipMode(noscriptTag); } return true; @@ -939,6 +938,7 @@ PassRefPtr<Node> HTMLParser::getNode(Token* t) gFunctionMap.set(h6Tag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); gFunctionMap.set(headTag.localName().impl(), &HTMLParser::headCreateErrorCheck); gFunctionMap.set(headerTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); + gFunctionMap.set(hgroupTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); gFunctionMap.set(hrTag.localName().impl(), &HTMLParser::pCloserCreateErrorCheck); gFunctionMap.set(iTag.localName().impl(), &HTMLParser::nestedStyleCreateErrorCheck); gFunctionMap.set(isindexTag.localName().impl(), &HTMLParser::isindexCreateErrorCheck); @@ -1061,8 +1061,8 @@ bool HTMLParser::isInline(Node* node) const return true; #if !ENABLE(XHTMLMP) if (e->hasLocalName(noscriptTag) && !m_isParsingFragment) { - Settings* settings = m_document->settings(); - if (settings && settings->isJavaScriptEnabled()) + Frame* frame = m_document->frame(); + if (frame && frame->script()->canExecuteScripts(NotAboutToExecuteScript)) return true; } #endif @@ -1590,12 +1590,16 @@ void HTMLParser::createHead() if (m_head) return; - if (!m_document->documentElement()) { + if (!m_document->documentElement() && !m_isParsingFragment) { insertNode(new HTMLHtmlElement(htmlTag, m_document)); - ASSERT(m_document->documentElement()); + ASSERT(m_document->documentElement() || m_isParsingFragment); } m_head = new HTMLHeadElement(headTag, m_document); + + if (m_isParsingFragment) + return; + HTMLElement* body = m_document->body(); ExceptionCode ec = 0; m_document->documentElement()->insertBefore(m_head.get(), body, ec); diff --git a/WebCore/html/HTMLPlugInImageElement.cpp b/WebCore/html/HTMLPlugInImageElement.cpp index 6dcd5fb..e2898a2 100644 --- a/WebCore/html/HTMLPlugInImageElement.cpp +++ b/WebCore/html/HTMLPlugInImageElement.cpp @@ -34,10 +34,6 @@ HTMLPlugInImageElement::HTMLPlugInImageElement(const QualifiedName& tagName, Doc { } -HTMLPlugInImageElement::~HTMLPlugInImageElement() -{ -} - bool HTMLPlugInImageElement::isImageType() { if (m_serviceType.isEmpty() && protocolIs(m_url, "data")) @@ -51,4 +47,11 @@ bool HTMLPlugInImageElement::isImageType() return Image::supportsType(m_serviceType); } +void HTMLPlugInImageElement::willMoveToNewOwnerDocument() +{ + if (m_imageLoader) + m_imageLoader->elementWillMoveToNewOwnerDocument(); + HTMLPlugInElement::willMoveToNewOwnerDocument(); +} + } // namespace WebCore diff --git a/WebCore/html/HTMLPlugInImageElement.h b/WebCore/html/HTMLPlugInImageElement.h index 7725a5a..6f8d305 100644 --- a/WebCore/html/HTMLPlugInImageElement.h +++ b/WebCore/html/HTMLPlugInImageElement.h @@ -30,8 +30,6 @@ class HTMLImageLoader; class HTMLPlugInImageElement : public HTMLPlugInElement { public: - virtual ~HTMLPlugInImageElement(); - const String& serviceType() const { return m_serviceType; } const String& url() const { return m_url; } @@ -43,6 +41,9 @@ protected: OwnPtr<HTMLImageLoader> m_imageLoader; String m_serviceType; String m_url; + +private: + virtual void willMoveToNewOwnerDocument(); }; } // namespace WebCore diff --git a/WebCore/html/HTMLProgressElement.cpp b/WebCore/html/HTMLProgressElement.cpp new file mode 100644 index 0000000..6fa8043 --- /dev/null +++ b/WebCore/html/HTMLProgressElement.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * 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" +#if ENABLE(PROGRESS_TAG) +#include "HTMLProgressElement.h" + +#include "EventNames.h" +#include "FormDataList.h" +#include "HTMLFormElement.h" +#include "HTMLNames.h" +#include "MappedAttribute.h" +#include "RenderProgress.h" +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +using namespace HTMLNames; + +HTMLProgressElement::HTMLProgressElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form) + : HTMLFormControlElement(tagName, document, form, CreateElement) +{ + ASSERT(hasTagName(progressTag)); +} + +PassRefPtr<HTMLProgressElement> HTMLProgressElement::create(const QualifiedName& tagName, Document* document, HTMLFormElement* form) +{ + return adoptRef(new HTMLProgressElement(tagName, document, form)); +} + +RenderObject* HTMLProgressElement::createRenderer(RenderArena* arena, RenderStyle*) +{ + return new (arena) RenderProgress(this); +} + +const AtomicString& HTMLProgressElement::formControlType() const +{ + DEFINE_STATIC_LOCAL(const AtomicString, progress, ("progress")); + return progress; +} + +void HTMLProgressElement::parseMappedAttribute(MappedAttribute* attribute) +{ + if (attribute->name() == valueAttr) { + if (renderer()) + renderer()->updateFromElement(); + } else if (attribute->name() == maxAttr) { + if (renderer()) + renderer()->updateFromElement(); + } else + HTMLFormControlElement::parseMappedAttribute(attribute); +} + +double HTMLProgressElement::value() const +{ + const AtomicString& valueString = getAttribute(valueAttr); + bool ok; + double value = valueString.toDouble(&ok); + if (!ok || value < 0) + return valueString.isNull() ? 1 : 0; + return (value > max()) ? max() : value; +} + +void HTMLProgressElement::setValue(double value) +{ + setAttribute(valueAttr, String::number(value >= 0 ? value : 0)); +} + +double HTMLProgressElement::max() const +{ + bool ok; + double max = getAttribute(maxAttr).toDouble(&ok); + if (!ok || max <= 0) + return 1; + return max; +} + +void HTMLProgressElement::setMax(double max) +{ + setAttribute(maxAttr, String::number(max > 0 ? max : 1)); +} + +double HTMLProgressElement::position() const +{ + if (!hasAttribute(valueAttr)) + return -1; + return value() / max(); +} + +} // namespace +#endif diff --git a/WebCore/html/HTMLProgressElement.h b/WebCore/html/HTMLProgressElement.h new file mode 100644 index 0000000..a925fc5 --- /dev/null +++ b/WebCore/html/HTMLProgressElement.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * 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 HTMLProgressElement_h +#define HTMLProgressElement_h + +#if ENABLE(PROGRESS_TAG) +#include "HTMLFormControlElement.h" + +namespace WebCore { + +class HTMLProgressElement : public HTMLFormControlElement { +public: + static PassRefPtr<HTMLProgressElement> create(const QualifiedName&, Document*, HTMLFormElement* = 0); + + double value() const; + void setValue(double); + + double max() const; + void setMax(double); + + double position() const; + +private: + HTMLProgressElement(const QualifiedName&, Document*, HTMLFormElement*); + + virtual bool isOptionalFormControl() const { return true; } + + virtual const AtomicString& formControlType() const; + + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + + virtual void parseMappedAttribute(MappedAttribute*); +}; + +} // namespace + +#endif +#endif diff --git a/WebCore/html/HTMLProgressElement.idl b/WebCore/html/HTMLProgressElement.idl new file mode 100644 index 0000000..8da62aa --- /dev/null +++ b/WebCore/html/HTMLProgressElement.idl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * 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. + */ + +module html { + interface [ + Conditional=PROGRESS_TAG + ] HTMLProgressElement : HTMLElement { + attribute double value; + attribute double max; + readonly attribute double position; + readonly attribute HTMLFormElement form; + }; + +} diff --git a/WebCore/html/HTMLScriptElement.cpp b/WebCore/html/HTMLScriptElement.cpp index 636c579..58c3b03 100644 --- a/WebCore/html/HTMLScriptElement.cpp +++ b/WebCore/html/HTMLScriptElement.cpp @@ -220,6 +220,11 @@ String HTMLScriptElement::forAttributeValue() const return getAttribute(forAttr).string(); } +String HTMLScriptElement::eventAttributeValue() const +{ + return getAttribute(eventAttr).string(); +} + void HTMLScriptElement::dispatchLoadEvent() { ASSERT(!m_data.haveFiredLoadEvent()); diff --git a/WebCore/html/HTMLScriptElement.h b/WebCore/html/HTMLScriptElement.h index 4d18beb..b6d683f 100644 --- a/WebCore/html/HTMLScriptElement.h +++ b/WebCore/html/HTMLScriptElement.h @@ -83,6 +83,7 @@ protected: virtual String typeAttributeValue() const; virtual String languageAttributeValue() const; virtual String forAttributeValue() const; + virtual String eventAttributeValue() const; virtual void dispatchLoadEvent(); virtual void dispatchErrorEvent(); diff --git a/WebCore/html/HTMLSelectElement.cpp b/WebCore/html/HTMLSelectElement.cpp index 5f5c855..de40ff7 100644 --- a/WebCore/html/HTMLSelectElement.cpp +++ b/WebCore/html/HTMLSelectElement.cpp @@ -1,4 +1,5 @@ /* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) @@ -87,9 +88,27 @@ void HTMLSelectElement::setSelectedIndex(int optionIndex, bool deselect) void HTMLSelectElement::setSelectedIndexByUser(int optionIndex, bool deselect, bool fireOnChangeNow) { + // Bail out if this index is already the selected one, to avoid running unnecessary JavaScript that can mess up + // autofill, when there is no actual change (see https://bugs.webkit.org/show_bug.cgi?id=35256 and rdar://7467917 ). + // Perhaps this logic could be moved into SelectElement, but some callers of SelectElement::setSelectedIndex() + // seem to expect it to fire its change event even when the index was already selected. + if (optionIndex == selectedIndex()) + return; + SelectElement::setSelectedIndex(m_data, this, optionIndex, deselect, fireOnChangeNow, true); } +void HTMLSelectElement::listBoxSelectItem(int listIndex, bool allowMultiplySelections, bool shift, bool fireOnChangeNow) +{ + if (!multiple()) + setSelectedIndexByUser(listIndex, true, fireOnChangeNow); + else { + updateSelectedState(m_data, this, listIndex, allowMultiplySelections, shift); + if (fireOnChangeNow) + listBoxOnChange(); + } +} + int HTMLSelectElement::activeSelectionStartListIndex() const { if (m_data.activeSelectionAnchorIndex() >= 0) @@ -181,8 +200,13 @@ void HTMLSelectElement::parseMappedAttribute(MappedAttribute* attr) String attrSize = String::number(size); if (attrSize != attr->value()) attr->setValue(attrSize); + size = max(size, 1); + + // Ensure that we've determined selectedness of the items at least once prior to changing the size. + if (oldSize != size) + recalcListItemsIfNeeded(); - m_data.setSize(max(size, 1)); + m_data.setSize(size); if ((oldUsesMenuList != m_data.usesMenuList() || (!oldUsesMenuList && m_data.size() != oldSize)) && attached()) { detach(); attach(); @@ -195,10 +219,6 @@ void HTMLSelectElement::parseMappedAttribute(MappedAttribute* attr) } else if (attr->name() == alignAttr) { // Don't map 'align' attribute. This matches what Firefox, Opera and IE do. // See http://bugs.webkit.org/show_bug.cgi?id=12072 - } else if (attr->name() == onfocusAttr) { - setAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(this, attr)); - } else if (attr->name() == onblurAttr) { - setAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(this, attr)); } else if (attr->name() == onchangeAttr) { setAttributeEventListener(eventNames().changeEvent, createAttributeEventListener(this, attr)); } else @@ -411,11 +431,21 @@ void HTMLSelectElement::setLength(unsigned newLen, ExceptionCode& ec) } else { const Vector<Element*>& items = listItems(); + // Removing children fires mutation events, which might mutate the DOM further, so we first copy out a list + // of elements that we intend to remove then attempt to remove them one at a time. + Vector<RefPtr<Element> > itemsToRemove; size_t optionIndex = 0; - for (size_t listIndex = 0; listIndex < items.size(); listIndex++) { - if (items[listIndex]->hasLocalName(optionTag) && optionIndex++ >= newLen) { - Element *item = items[listIndex]; + for (size_t i = 0; i < items.size(); ++i) { + Element* item = items[i]; + if (item->hasLocalName(optionTag) && optionIndex++ >= newLen) { ASSERT(item->parentNode()); + itemsToRemove.append(item); + } + } + + for (size_t i = 0; i < itemsToRemove.size(); ++i) { + Element* item = itemsToRemove[i].get(); + if (item->parentNode()) { item->parentNode()->removeChild(item, ec); } } diff --git a/WebCore/html/HTMLSelectElement.h b/WebCore/html/HTMLSelectElement.h index 0a2050e..8a31efc 100644 --- a/WebCore/html/HTMLSelectElement.h +++ b/WebCore/html/HTMLSelectElement.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) @@ -80,6 +81,8 @@ public: void scrollToSelection(); + void listBoxSelectItem(int listIndex, bool allowMultiplySelections, bool shift, bool fireOnChangeNow = true); + private: virtual int tagPriority() const { return 6; } virtual bool checkDTD(const Node* newChild); diff --git a/WebCore/html/HTMLTagNames.in b/WebCore/html/HTMLTagNames.in index 430b8ea..9f4900c 100644 --- a/WebCore/html/HTMLTagNames.in +++ b/WebCore/html/HTMLTagNames.in @@ -55,6 +55,7 @@ h5 interfaceName=HTMLHeadingElement, createWithNew h6 interfaceName=HTMLHeadingElement, createWithNew head createWithNew header interfaceName=HTMLElement +hgroup interfaceName=HTMLElement hr interfaceName=HTMLHRElement, createWithNew html createWithNew i interfaceName=HTMLElement @@ -89,6 +90,7 @@ p interfaceName=HTMLParagraphElement, createWithNew param createWithNew plaintext interfaceName=HTMLElement pre createWithNew +progress interfaceName=HTMLProgressElement, conditional=PROGRESS_TAG q interfaceName=HTMLQuoteElement, createWithNew rp interfaceName=HTMLElement, conditional=RUBY rt interfaceName=HTMLElement, conditional=RUBY diff --git a/WebCore/html/HTMLTextAreaElement.cpp b/WebCore/html/HTMLTextAreaElement.cpp index 633e5ec..2bfde03 100644 --- a/WebCore/html/HTMLTextAreaElement.cpp +++ b/WebCore/html/HTMLTextAreaElement.cpp @@ -90,7 +90,10 @@ const AtomicString& HTMLTextAreaElement::formControlType() const bool HTMLTextAreaElement::saveFormControlState(String& result) const { - result = value(); + String currentValue = value(); + if (currentValue == defaultValue()) + return false; + result = currentValue; return true; } @@ -170,6 +173,8 @@ bool HTMLTextAreaElement::appendFormData(FormDataList& encoding, bool) if (name().isEmpty()) return false; + document()->updateLayout(); + // FIXME: It's not acceptable to ignore the HardWrap setting when there is no renderer. // While we have no evidence this has ever been a practical problem, it would be best to fix it some day. RenderTextControl* control = toRenderTextControl(renderer()); @@ -239,8 +244,8 @@ void HTMLTextAreaElement::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* return; unsigned unsignedMaxLength = static_cast<unsigned>(signedMaxLength); - unsigned currentLength = toRenderTextControl(renderer())->text().numGraphemeClusters(); - unsigned selectionLength = plainText(document()->frame()->selection()->selection().toNormalizedRange().get()).numGraphemeClusters(); + unsigned currentLength = numGraphemeClusters(toRenderTextControl(renderer())->text()); + unsigned selectionLength = numGraphemeClusters(plainText(document()->frame()->selection()->selection().toNormalizedRange().get())); ASSERT(currentLength >= selectionLength); unsigned baseLength = currentLength - selectionLength; unsigned appendableLength = unsignedMaxLength > baseLength ? unsignedMaxLength - baseLength : 0; @@ -249,7 +254,7 @@ void HTMLTextAreaElement::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* String HTMLTextAreaElement::sanitizeUserInputValue(const String& proposedValue, unsigned maxLength) { - return proposedValue.left(proposedValue.numCharactersInGraphemeClusters(maxLength)); + return proposedValue.left(numCharactersInGraphemeClusters(proposedValue, maxLength)); } void HTMLTextAreaElement::rendererWillBeDestroyed() @@ -295,13 +300,11 @@ void HTMLTextAreaElement::setNonDirtyValue(const String& value) return; m_value = normalizedValue; + updatePlaceholderVisibility(false); + setNeedsStyleRecalc(); + setNeedsValidityCheck(); m_isDirty = false; setFormControlValueMatchesRenderer(true); - updatePlaceholderVisibility(false); - if (inDocument()) - document()->updateStyleIfNeeded(); - if (renderer()) - renderer()->updateFromElement(); // Set the caret to the end of the text value. if (document()->focusedNode() == this) { @@ -313,7 +316,6 @@ void HTMLTextAreaElement::setNonDirtyValue(const String& value) setSelectionRange(endOfString, endOfString); } - setNeedsValidityCheck(); notifyFormStateChanged(this); } @@ -388,7 +390,7 @@ bool HTMLTextAreaElement::tooLong() const int max = maxLength(); if (max < 0) return false; - return value().numGraphemeClusters() > static_cast<unsigned>(max); + return numGraphemeClusters(value()) > static_cast<unsigned>(max); } void HTMLTextAreaElement::accessKeyAction(bool) diff --git a/WebCore/html/HTMLTitleElement.cpp b/WebCore/html/HTMLTitleElement.cpp index b9a8de7..81ecd10 100644 --- a/WebCore/html/HTMLTitleElement.cpp +++ b/WebCore/html/HTMLTitleElement.cpp @@ -84,10 +84,15 @@ void HTMLTitleElement::setText(const String &value) if (numChildren == 1 && firstChild()->isTextNode()) static_cast<Text*>(firstChild())->setData(value, ec); else { + // We make a copy here because entity of "value" argument can be Document::m_title, + // which goes empty during removeChildren() invocation below, + // which causes HTMLTitleElement::childrenChanged(), which ends up Document::setTitle(). + String valueCopy(value); + if (numChildren > 0) removeChildren(); - - appendChild(document()->createTextNode(value.impl()), ec); + + appendChild(document()->createTextNode(valueCopy.impl()), ec); } } diff --git a/WebCore/html/HTMLTokenizer.cpp b/WebCore/html/HTMLTokenizer.cpp index 6fa3e20..390d332 100644 --- a/WebCore/html/HTMLTokenizer.cpp +++ b/WebCore/html/HTMLTokenizer.cpp @@ -71,25 +71,17 @@ namespace WebCore { using namespace HTMLNames; -#if MOBILE -// The mobile device needs to be responsive, as such the tokenizer chunk size is reduced. // This value is used to define how many characters the tokenizer will process before // yeilding control. -static const int defaultTokenizerChunkSize = 256; -#else +// To increase responsivness reduce the tokenizer chunk size. static const int defaultTokenizerChunkSize = 4096; -#endif -#if MOBILE -// As the chunks are smaller (above), the tokenizer should not yield for as long a period, otherwise -// it will take way to long to load a page. -static const double defaultTokenizerTimeDelay = 0.300; -#else // 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. +// For smaller chunks (above) decrease the value of TimerDelay as the the tokenizer should not +// yield for as long a period otherwise it will take way to long to load a page. static const double defaultTokenizerTimeDelay = 0.500; -#endif static const char commentStart [] = "<!--"; static const char doctypeStart [] = "<!doctype"; @@ -1523,7 +1515,7 @@ HTMLTokenizer::State HTMLTokenizer::parseTag(SegmentedString& src, State state) m_scriptTagSrcAttrValue = String(); m_scriptTagCharsetAttrValue = String(); if (m_currentToken.attrs && !m_fragment) { - if (m_doc->frame() && m_doc->frame()->script()->canExecuteScripts()) { + if (m_doc->frame() && m_doc->frame()->script()->canExecuteScripts(NotAboutToExecuteScript)) { if ((a = m_currentToken.attrs->getAttributeItem(srcAttr))) m_scriptTagSrcAttrValue = m_doc->completeURL(deprecatedParseURL(a->value())).string(); } @@ -1940,7 +1932,7 @@ void HTMLTokenizer::finish() PassRefPtr<Node> HTMLTokenizer::processToken() { ScriptController* scriptController = (!m_fragment && m_doc->frame()) ? m_doc->frame()->script() : 0; - if (scriptController && scriptController->canExecuteScripts()) + if (scriptController && scriptController->canExecuteScripts(NotAboutToExecuteScript)) // FIXME: Why isn't this m_currentScriptTagStartLineNumber? I suspect this is wrong. scriptController->setEventHandlerLineNumber(m_currentTagStartLineNumber + 1); // Script line numbers are 1 based. if (m_dest > m_buffer) { diff --git a/WebCore/html/HTMLVideoElement.cpp b/WebCore/html/HTMLVideoElement.cpp index be8f884..3db48f1 100644 --- a/WebCore/html/HTMLVideoElement.cpp +++ b/WebCore/html/HTMLVideoElement.cpp @@ -104,8 +104,8 @@ void HTMLVideoElement::parseMappedAttribute(MappedAttribute* attr) m_imageLoader.set(new HTMLImageLoader(this)); m_imageLoader->updateFromElementIgnoringPreviousError(); #else - if (m_player) - m_player->setPoster(poster()); + if (player()) + player()->setPoster(poster()); #endif } } else if (attrName == widthAttr) @@ -122,7 +122,7 @@ bool HTMLVideoElement::supportsFullscreen() const if (!page) return false; - if (!m_player || !m_player->supportsFullscreen() || !m_player->hasVideo()) + if (!player() || !player()->supportsFullscreen() || !player()->hasVideo()) return false; // Check with the platform client. @@ -131,16 +131,16 @@ bool HTMLVideoElement::supportsFullscreen() const unsigned HTMLVideoElement::videoWidth() const { - if (!m_player) + if (!player()) return 0; - return m_player->naturalSize().width(); + return player()->naturalSize().width(); } unsigned HTMLVideoElement::videoHeight() const { - if (!m_player) + if (!player()) return 0; - return m_player->naturalSize().height(); + return player()->naturalSize().height(); } unsigned HTMLVideoElement::width() const @@ -196,16 +196,6 @@ void HTMLVideoElement::updatePosterImage() #endif } -void HTMLVideoElement::paint(GraphicsContext* context, const IntRect& destRect) -{ - MediaPlayer* player = HTMLMediaElement::player(); - if (!player) - return; - - player->setVisible(true); // Make player visible or it won't draw. - player->paint(context, destRect); -} - void HTMLVideoElement::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& destRect) { MediaPlayer* player = HTMLMediaElement::player(); @@ -218,15 +208,15 @@ void HTMLVideoElement::paintCurrentFrameInContext(GraphicsContext* context, cons bool HTMLVideoElement::hasAvailableVideoFrame() const { - if (!m_player) + if (!player()) return false; - return m_player->hasAvailableVideoFrame(); + return player()->hasAvailableVideoFrame(); } -void HTMLVideoElement::webkitEnterFullScreen(bool isUserGesture, ExceptionCode& ec) +void HTMLVideoElement::webkitEnterFullscreen(bool isUserGesture, ExceptionCode& ec) { - if (m_isFullscreen) + if (isFullscreen()) return; // Generate an exception if this isn't called in response to a user gesture, or if the @@ -239,9 +229,9 @@ void HTMLVideoElement::webkitEnterFullScreen(bool isUserGesture, ExceptionCode& enterFullscreen(); } -void HTMLVideoElement::webkitExitFullScreen() +void HTMLVideoElement::webkitExitFullscreen() { - if (m_isFullscreen) + if (isFullscreen()) exitFullscreen(); } @@ -252,9 +242,15 @@ bool HTMLVideoElement::webkitSupportsFullscreen() bool HTMLVideoElement::webkitDisplayingFullscreen() { - return m_isFullscreen; + return isFullscreen(); } +void HTMLVideoElement::willMoveToNewOwnerDocument() +{ + if (m_imageLoader) + m_imageLoader->elementWillMoveToNewOwnerDocument(); + HTMLMediaElement::willMoveToNewOwnerDocument(); +} } #endif diff --git a/WebCore/html/HTMLVideoElement.h b/WebCore/html/HTMLVideoElement.h index d12667e..4dad3db 100644 --- a/WebCore/html/HTMLVideoElement.h +++ b/WebCore/html/HTMLVideoElement.h @@ -29,7 +29,6 @@ #if ENABLE(VIDEO) #include "HTMLMediaElement.h" -#include <wtf/OwnPtr.h> namespace WebCore { @@ -39,20 +38,6 @@ class HTMLVideoElement : public HTMLMediaElement { public: HTMLVideoElement(const QualifiedName&, Document*); - virtual int tagPriority() const { return 5; } - virtual bool rendererIsNeeded(RenderStyle*); -#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO) - virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); -#endif - virtual void attach(); - virtual void detach(); - virtual void parseMappedAttribute(MappedAttribute* attr); - virtual bool isVideo() const { return true; } - virtual bool hasVideo() const { return player() && player()->hasVideo(); } - virtual bool supportsFullscreen() const; - virtual bool isURLAttribute(Attribute*) const; - virtual const QualifiedName& imageSourceAttributeName() const; - unsigned width() const; void setWidth(unsigned); unsigned height() const; @@ -61,24 +46,43 @@ public: unsigned videoWidth() const; unsigned videoHeight() const; - const KURL& poster() const { return m_posterURL; } + virtual const KURL poster() const { return m_posterURL; } void setPoster(const String&); -// fullscreen - void webkitEnterFullScreen(bool isUserGesture, ExceptionCode&); - void webkitExitFullScreen(); + // Fullscreen + void webkitEnterFullscreen(bool isUserGesture, ExceptionCode&); + void webkitExitFullscreen(); bool webkitSupportsFullscreen(); bool webkitDisplayingFullscreen(); + // FIXME: Maintain "FullScreen" capitalization scheme for backwards compatibility. + // https://bugs.webkit.org/show_bug.cgi?id=36081 + void webkitEnterFullScreen(bool isUserGesture, ExceptionCode& ec) { webkitEnterFullscreen(isUserGesture, ec); } + void webkitExitFullScreen() { webkitExitFullscreen(); } + bool shouldDisplayPosterImage() const { return m_shouldDisplayPosterImage; } - void paint(GraphicsContext*, const IntRect&); // Used by canvas to gain raw pixel access void paintCurrentFrameInContext(GraphicsContext*, const IntRect&); private: + virtual int tagPriority() const { return 5; } + virtual bool rendererIsNeeded(RenderStyle*); +#if !ENABLE(PLUGIN_PROXY_FOR_VIDEO) + virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); +#endif + virtual void attach(); + virtual void detach(); + virtual void parseMappedAttribute(MappedAttribute*); + virtual bool isVideo() const { return true; } + virtual bool hasVideo() const { return player() && player()->hasVideo(); } + virtual bool supportsFullscreen() const; + virtual bool isURLAttribute(Attribute*) const; + virtual const QualifiedName& imageSourceAttributeName() const; + virtual bool hasAvailableVideoFrame() const; virtual void updatePosterImage(); + virtual void willMoveToNewOwnerDocument(); OwnPtr<HTMLImageLoader> m_imageLoader; KURL m_posterURL; diff --git a/WebCore/html/HTMLVideoElement.idl b/WebCore/html/HTMLVideoElement.idl index c4764ac..1b21c54 100644 --- a/WebCore/html/HTMLVideoElement.idl +++ b/WebCore/html/HTMLVideoElement.idl @@ -33,6 +33,10 @@ module html { readonly attribute boolean webkitSupportsFullscreen; readonly attribute boolean webkitDisplayingFullscreen; + + [NeedsUserGestureCheck] void webkitEnterFullscreen() + raises (DOMException); + void webkitExitFullscreen(); [NeedsUserGestureCheck] void webkitEnterFullScreen() raises (DOMException); diff --git a/WebCore/html/HTMLViewSourceDocument.cpp b/WebCore/html/HTMLViewSourceDocument.cpp index ba718d1..2d800b4 100644 --- a/WebCore/html/HTMLViewSourceDocument.cpp +++ b/WebCore/html/HTMLViewSourceDocument.cpp @@ -54,7 +54,7 @@ HTMLViewSourceDocument::HTMLViewSourceDocument(Frame* frame, const String& mimeT Tokenizer* HTMLViewSourceDocument::createTokenizer() { // Use HTMLTokenizer if applicable, otherwise use TextTokenizer. - if (m_type == "text/html" || m_type == "application/xhtml+xml" || m_type == "image/svg+xml" || implementation()->isXMLMIMEType(m_type) + 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 diff --git a/WebCore/html/PreloadScanner.cpp b/WebCore/html/PreloadScanner.cpp index 527b9f8..ee7e761 100644 --- a/WebCore/html/PreloadScanner.cpp +++ b/WebCore/html/PreloadScanner.cpp @@ -34,13 +34,13 @@ #include "CachedResourceClient.h" #include "CachedScript.h" #include "CSSHelper.h" -#include "CString.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> diff --git a/WebCore/html/StepRange.cpp b/WebCore/html/StepRange.cpp new file mode 100644 index 0000000..7c270f2 --- /dev/null +++ b/WebCore/html/StepRange.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009, 2010 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. + * + */ + +#include "config.h" +#include "StepRange.h" + +#include "HTMLInputElement.h" +#include "HTMLNames.h" +#include "PlatformString.h" +#include <wtf/MathExtras.h> + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +StepRange::StepRange(const HTMLInputElement* element) +{ + if (element->hasAttribute(precisionAttr)) { + step = 1.0; + hasStep = !equalIgnoringCase(element->getAttribute(precisionAttr), "float"); + } else + hasStep = element->getAllowedValueStep(&step); + + maximum = element->maximum(); + minimum = element->minimum(); +} + +double StepRange::clampValue(double value) +{ + double clampedValue = max(minimum, min(value, maximum)); + if (!hasStep) + return clampedValue; + // Rounds clampedValue to minimum + N * step. + clampedValue = minimum + round((clampedValue - minimum) / step) * step; + if (clampedValue > maximum) + clampedValue -= step; + ASSERT(clampedValue >= minimum); + ASSERT(clampedValue <= maximum); + return clampedValue; +} + +double StepRange::clampValue(const String& stringValue) +{ + double value; + bool parseSuccess = HTMLInputElement::parseToDoubleForNumberType(stringValue, &value); + if (!parseSuccess) + value = (minimum + maximum) / 2; + return clampValue(value); +} + +double StepRange::valueFromElement(HTMLInputElement* element, bool* wasClamped) +{ + double oldValue; + bool parseSuccess = HTMLInputElement::parseToDoubleForNumberType(element->value(), &oldValue); + if (!parseSuccess) + oldValue = (minimum + maximum) / 2; + double newValue = clampValue(oldValue); + + if (wasClamped) + *wasClamped = !parseSuccess || newValue != oldValue; + + return newValue; +} + +} diff --git a/WebCore/html/StepRange.h b/WebCore/html/StepRange.h new file mode 100644 index 0000000..2f5013a --- /dev/null +++ b/WebCore/html/StepRange.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2006, 2007, 2008, 2009, 2010 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 StepRange_h +#define StepRange_h + +#include <wtf/Noncopyable.h> + +namespace WebCore { + +class HTMLInputElement; +class String; + +class StepRange : public Noncopyable { +public: + bool hasStep; + double step; + double minimum; + double maximum; // maximum must be >= minimum. + + explicit StepRange(const HTMLInputElement*); + double clampValue(double value); + double clampValue(const String& stringValue); + + // Clamp the middle value according to the step + double defaultValue() + { + return clampValue((minimum + maximum) / 2); + } + + // Map value into 0-1 range + double proportionFromValue(double value) + { + if (minimum == maximum) + return 0; + + return (value - minimum) / (maximum - minimum); + } + + // Map from 0-1 range to value + double valueFromProportion(double proportion) + { + return minimum + proportion * (maximum - minimum); + } + + double valueFromElement(HTMLInputElement*, bool* wasClamped = 0); +}; + +} + +#endif // StepRange_h diff --git a/WebCore/html/canvas/CanvasRenderingContext2D.cpp b/WebCore/html/canvas/CanvasRenderingContext2D.cpp index 6fe74f9..0baa0e6 100644 --- a/WebCore/html/canvas/CanvasRenderingContext2D.cpp +++ b/WebCore/html/canvas/CanvasRenderingContext2D.cpp @@ -39,7 +39,6 @@ #include "CSSMutableStyleDeclaration.h" #include "CSSPropertyNames.h" #include "CSSStyleSelector.h" -#include "Document.h" #include "ExceptionCode.h" #include "FloatConversion.h" #include "GraphicsContext.h" @@ -90,12 +89,18 @@ private: CanvasRenderingContext2D* m_canvasContext; }; - - -CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas) +CanvasRenderingContext2D::CanvasRenderingContext2D(HTMLCanvasElement* canvas, bool usesCSSCompatibilityParseMode, bool usesDashboardCompatibilityMode) : CanvasRenderingContext(canvas) , m_stateStack(1) + , m_usesCSSCompatibilityParseMode(usesCSSCompatibilityParseMode) +#if ENABLE(DASHBOARD_SUPPORT) + , m_usesDashboardCompatibilityMode(usesDashboardCompatibilityMode) +#endif { +#if !ENABLE(DASHBOARD_SUPPORT) + ASSERT_UNUSED(usesDashboardCompatibilityMode, !usesDashboardCompatibilityMode); +#endif + // Make sure that even if the drawingContext() has a different default // thickness, it is in sync with the canvas thickness. setLineWidth(lineWidth()); @@ -636,9 +641,8 @@ void CanvasRenderingContext2D::rect(float x, float y, float width, float height) #if ENABLE(DASHBOARD_SUPPORT) void CanvasRenderingContext2D::clearPathForDashboardBackwardCompatibilityMode() { - if (Settings* settings = canvas()->document()->settings()) - if (settings->usesDashboardBackwardCompatibilityMode()) - m_path.clear(); + if (m_usesDashboardCompatibilityMode) + m_path.clear(); } #endif @@ -941,7 +945,7 @@ static inline FloatRect normalizeRect(const FloatRect& rect) void CanvasRenderingContext2D::checkOrigin(const KURL& url) { - if (canvas()->document()->securityOrigin()->taintsCanvas(url)) + if (canvas()->securityOrigin().taintsCanvas(url)) canvas()->setOriginTainted(); } @@ -950,26 +954,45 @@ void CanvasRenderingContext2D::checkOrigin(const String& url) checkOrigin(KURL(KURL(), url)); } -void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, float x, float y) +void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, float x, float y, ExceptionCode& ec) { - ASSERT(image); + if (!image) { + ec = TYPE_MISMATCH_ERR; + return; + } IntSize s = size(image); - ExceptionCode ec; drawImage(image, x, y, s.width(), s.height(), ec); } void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, float x, float y, float width, float height, ExceptionCode& ec) { - ASSERT(image); + if (!image) { + ec = TYPE_MISMATCH_ERR; + return; + } IntSize s = size(image); drawImage(image, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec); } +void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, + float sx, float sy, float sw, float sh, + float dx, float dy, float dw, float dh, ExceptionCode& ec) +{ + if (!image) { + ec = TYPE_MISMATCH_ERR; + return; + } + drawImage(image, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), ec); +} + void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode& ec) { - ASSERT(image); + if (!image) { + ec = TYPE_MISMATCH_ERR; + return; + } ec = 0; @@ -1004,24 +1027,39 @@ void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRec c->drawImage(cachedImage->image(), DeviceColorSpace, destRect, sourceRect, state().m_globalComposite); } -void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, float x, float y) +void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, float x, float y, ExceptionCode& ec) { - ASSERT(canvas); - ExceptionCode ec; + if (!canvas) { + ec = TYPE_MISMATCH_ERR; + return; + } drawImage(canvas, x, y, canvas->width(), canvas->height(), ec); } void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, float x, float y, float width, float height, ExceptionCode& ec) { - ASSERT(canvas); + if (!canvas) { + ec = TYPE_MISMATCH_ERR; + return; + } drawImage(canvas, FloatRect(0, 0, canvas->width(), canvas->height()), FloatRect(x, y, width, height), ec); } +void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* canvas, + float sx, float sy, float sw, float sh, + float dx, float dy, float dw, float dh, ExceptionCode& ec) +{ + drawImage(canvas, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), ec); +} + void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode& ec) { - ASSERT(sourceCanvas); + if (!sourceCanvas) { + ec = TYPE_MISMATCH_ERR; + return; + } ec = 0; @@ -1057,26 +1095,41 @@ void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, const } #if ENABLE(VIDEO) -void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, float x, float y) +void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, float x, float y, ExceptionCode& ec) { - ASSERT(video); + if (!video) { + ec = TYPE_MISMATCH_ERR; + return; + } IntSize s = size(video); - ExceptionCode ec; drawImage(video, x, y, s.width(), s.height(), ec); } void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, float x, float y, float width, float height, ExceptionCode& ec) { - ASSERT(video); + if (!video) { + ec = TYPE_MISMATCH_ERR; + return; + } IntSize s = size(video); drawImage(video, FloatRect(0, 0, s.width(), s.height()), FloatRect(x, y, width, height), ec); } +void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, + float sx, float sy, float sw, float sh, + float dx, float dy, float dw, float dh, ExceptionCode& ec) +{ + drawImage(video, FloatRect(sx, sy, sw, sh), FloatRect(dx, dy, dw, dh), ec); +} + void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode& ec) { - ASSERT(video); + if (!video) { + ec = TYPE_MISMATCH_ERR; + return; + } ec = 0; FloatRect videoRect = FloatRect(FloatPoint(), size(video)); @@ -1161,9 +1214,8 @@ void CanvasRenderingContext2D::setCompositeOperation(const String& operation) void CanvasRenderingContext2D::prepareGradientForDashboard(CanvasGradient* gradient) const { #if ENABLE(DASHBOARD_SUPPORT) - if (Settings* settings = canvas()->document()->settings()) - if (settings->usesDashboardBackwardCompatibilityMode()) - gradient->setDashboardCompatibilityMode(); + if (m_usesDashboardCompatibilityMode) + gradient->setDashboardCompatibilityMode(); #else UNUSED_PARAM(gradient); #endif @@ -1196,6 +1248,10 @@ PassRefPtr<CanvasGradient> CanvasRenderingContext2D::createRadialGradient(float PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLImageElement* image, const String& repetitionType, ExceptionCode& ec) { + if (!image) { + ec = TYPE_MISMATCH_ERR; + return 0; + } bool repeatX, repeatY; ec = 0; CanvasPattern::parseRepetitionType(repetitionType, repeatX, repeatY, ec); @@ -1211,13 +1267,21 @@ PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLImageEleme if (!cachedImage || !image->cachedImage()->image()) return CanvasPattern::create(Image::nullImage(), repeatX, repeatY, true); +<<<<<<< HEAD bool originClean = !canvas()->document()->securityOrigin()->taintsCanvas(KURL(KURL(), cachedImage->url())) && cachedImage->image()->hasSingleSecurityOrigin(); +======= + bool originClean = !canvas()->securityOrigin().taintsCanvas(KURL(KURL(), cachedImage->url())) && cachedImage->image()->hasSingleSecurityOrigin(); +>>>>>>> webkit.org at r58033 return CanvasPattern::create(cachedImage->image(), repeatX, repeatY, originClean); } PassRefPtr<CanvasPattern> CanvasRenderingContext2D::createPattern(HTMLCanvasElement* canvas, const String& repetitionType, ExceptionCode& ec) { + if (!canvas) { + ec = TYPE_MISMATCH_ERR; + return 0; + } if (!canvas->width() || !canvas->height()) { ec = INVALID_STATE_ERR; return 0; @@ -1369,7 +1433,7 @@ String CanvasRenderingContext2D::font() const void CanvasRenderingContext2D::setFont(const String& newFont) { RefPtr<CSSMutableStyleDeclaration> tempDecl = CSSMutableStyleDeclaration::create(); - CSSParser parser(!canvas()->document()->inCompatMode()); // Use the parse mode of the canvas' document when parsing CSS. + CSSParser parser(!m_usesCSSCompatibilityParseMode); String declarationText("font: "); declarationText += newFont; @@ -1383,11 +1447,11 @@ void CanvasRenderingContext2D::setFont(const String& newFont) // Map the <canvas> font into the text style. If the font uses keywords like larger/smaller, these will work // relative to the canvas. RefPtr<RenderStyle> newStyle = RenderStyle::create(); - if (canvas()->computedStyle()) - newStyle->setFontDescription(canvas()->computedStyle()->fontDescription()); + if (RenderStyle* computedStyle = canvas()->computedStyle()) + newStyle->setFontDescription(computedStyle->fontDescription()); // Now map the font property into the style. - CSSStyleSelector* styleSelector = canvas()->document()->styleSelector(); + CSSStyleSelector* styleSelector = canvas()->styleSelector(); styleSelector->applyPropertyToStyle(CSSPropertyFont, tempDecl->getPropertyCSSValue(CSSPropertyFont).get(), newStyle.get()); state().m_font = newStyle->font(); @@ -1461,8 +1525,9 @@ void CanvasRenderingContext2D::drawTextInternal(const String& text, float x, flo // FIXME: Handle maxWidth. // FIXME: Need to turn off font smoothing. - bool rtl = canvas()->computedStyle() ? canvas()->computedStyle()->direction() == RTL : false; - bool override = canvas()->computedStyle() ? canvas()->computedStyle()->unicodeBidi() == Override : false; + RenderStyle* computedStyle = canvas()->computedStyle(); + bool rtl = computedStyle ? computedStyle->direction() == RTL : false; + bool override = computedStyle ? computedStyle->unicodeBidi() == Override : false; unsigned length = text.length(); const UChar* string = text.characters(); diff --git a/WebCore/html/canvas/CanvasRenderingContext2D.h b/WebCore/html/canvas/CanvasRenderingContext2D.h index 553ffd2..2bac902 100644 --- a/WebCore/html/canvas/CanvasRenderingContext2D.h +++ b/WebCore/html/canvas/CanvasRenderingContext2D.h @@ -57,7 +57,7 @@ namespace WebCore { class CanvasRenderingContext2D : public CanvasRenderingContext { public: - CanvasRenderingContext2D(HTMLCanvasElement*); + CanvasRenderingContext2D(HTMLCanvasElement*, bool usesCSSCompatibilityParseMode, bool usesDashboardCompatibilityMode); virtual ~CanvasRenderingContext2D(); @@ -154,15 +154,18 @@ namespace WebCore { void clearShadow(); - void drawImage(HTMLImageElement*, float x, float y); + void drawImage(HTMLImageElement*, float x, float y, ExceptionCode&); void drawImage(HTMLImageElement*, float x, float y, float width, float height, ExceptionCode&); + void drawImage(HTMLImageElement*, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, ExceptionCode&); void drawImage(HTMLImageElement*, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode&); - void drawImage(HTMLCanvasElement*, float x, float y); + void drawImage(HTMLCanvasElement*, float x, float y, ExceptionCode&); void drawImage(HTMLCanvasElement*, float x, float y, float width, float height, ExceptionCode&); + void drawImage(HTMLCanvasElement*, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, ExceptionCode&); void drawImage(HTMLCanvasElement*, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode&); #if ENABLE(VIDEO) - void drawImage(HTMLVideoElement*, float x, float y); + void drawImage(HTMLVideoElement*, float x, float y, ExceptionCode&); void drawImage(HTMLVideoElement*, float x, float y, float width, float height, ExceptionCode&); + void drawImage(HTMLVideoElement*, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh, ExceptionCode&); void drawImage(HTMLVideoElement*, const FloatRect& srcRect, const FloatRect& dstRect, ExceptionCode&); #endif @@ -263,6 +266,10 @@ namespace WebCore { void checkOrigin(const String&); Vector<State, 1> m_stateStack; + bool m_usesCSSCompatibilityParseMode; +#if ENABLE(DASHBOARD_SUPPORT) + bool m_usesDashboardCompatibilityMode; +#endif }; } // namespace WebCore diff --git a/WebCore/html/canvas/CanvasRenderingContext2D.idl b/WebCore/html/canvas/CanvasRenderingContext2D.idl index f93a752..a3c83ca 100644 --- a/WebCore/html/canvas/CanvasRenderingContext2D.idl +++ b/WebCore/html/canvas/CanvasRenderingContext2D.idl @@ -20,7 +20,7 @@ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ module html { @@ -82,8 +82,7 @@ module html { attribute DOMString font; attribute DOMString textAlign; attribute DOMString textBaseline; - [Custom] void fillText(/* 4 */); - [Custom] void strokeText(/* 4 */); + TextMetrics measureText(in DOMString text); // other @@ -98,6 +97,61 @@ module html { void clearShadow(); +#if defined(V8_BINDING) && V8_BINDING + void fillText(in DOMString text, in float x, in float y, in [Optional] float maxWidth); + void strokeText(in DOMString text, in float x, in float y, in [Optional] float maxWidth); + + void setStrokeColor(in DOMString color, in [Optional] float alpha); + void setStrokeColor(in float grayLevel, in [Optional] float alpha); + void setStrokeColor(in float r, in float g, in float b, in float a); + void setStrokeColor(in float c, in float m, in float y, in float k, in float a); + + void setFillColor(in DOMString color, in [Optional] float alpha); + void setFillColor(in float grayLevel, in [Optional] float alpha); + void setFillColor(in float r, in float g, in float b, in float a); + void setFillColor(in float c, in float m, in float y, in float k, in float a); + + void strokeRect(in float x, in float y, in float width, in float height, in [Optional] float lineWidth); + + void drawImage(in HTMLImageElement image, in float x, in float y) + raises (DOMException); + void drawImage(in HTMLImageElement image, in float x, in float y, in float width, in float height) + raises (DOMException); + void drawImage(in HTMLImageElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh) + raises (DOMException); + void drawImage(in HTMLCanvasElement canvas, in float x, in float y) + raises (DOMException); + void drawImage(in HTMLCanvasElement canvas, in float x, in float y, in float width, in float height) + raises (DOMException); + void drawImage(in HTMLCanvasElement canvas, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh) + raises (DOMException); +#if defined(ENABLE_VIDEO) && ENABLE_VIDEO + void drawImage(in HTMLVideoElement video, in float x, in float y) + raises (DOMException); + void drawImage(in HTMLVideoElement video, in float x, in float y, in float width, in float height) + raises (DOMException); + void drawImage(in HTMLVideoElement video, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh) + raises (DOMException); +#endif + void drawImageFromRect(in HTMLImageElement image, + in float sx, in float sy, in float sw, in float sh, + in float dx, in float dy, in float dw, in float dh, in DOMString compositeOperation); + + void setShadow(in float width, in float height, in float blur, in [Optional] DOMString color, in [Optional] float alpha); + void setShadow(in float width, in float height, in float blur, in float grayLevel, in [Optional] float alpha); + void setShadow(in float width, in float height, in float blur, in float r, in float g, in float b, in float a); + void setShadow(in float width, in float height, in float blur, in float c, in float m, in float y, in float k, in float a); + + CanvasPattern createPattern(in HTMLCanvasElement canvas, in [ConvertNullToNullString] DOMString repetitionType) + raises (DOMException); + CanvasPattern createPattern(in HTMLImageElement image, in [ConvertNullToNullString] DOMString repetitionType) + raises (DOMException); + void putImageData(in ImageData imagedata, in float dx, in float dy, in [Optional] float dirtyX, in float dirtyY, in float dirtyWidth, in float dirtyHeight) + raises(DOMException); +#else + // FIXME: Remove 'else' once JSC supports overloads too. + [Custom] void fillText(/* 4 */); + [Custom] void strokeText(/* 4 */); [Custom] void setStrokeColor(/* 1 */); [Custom] void setFillColor(/* 1 */); [Custom] void strokeRect(/* 4 */); @@ -105,16 +159,17 @@ module html { [Custom] void drawImageFromRect(/* 10 */); [Custom] void setShadow(/* 3 */); [Custom] void createPattern(/* 2 */); - + [Custom] void putImageData(/* in ImageData imagedata, in float dx, in float dy [, in float dirtyX, in float dirtyY, in float dirtyWidth, in float dirtyHeight] */); +#endif // defined(V8_BINDING) + attribute [Custom] custom strokeStyle; attribute [Custom] custom fillStyle; - + // pixel manipulation ImageData createImageData(in float sw, in float sh) raises (DOMException); ImageData getImageData(in float sx, in float sy, in float sw, in float sh) raises(DOMException); - [Custom] void putImageData(/* in ImageData imagedata, in float dx, in float dy [, in float dirtyX, in float dirtyY, in float dirtyWidth, in float dirtyHeight] */); }; } diff --git a/WebCore/html/canvas/CanvasStyle.cpp b/WebCore/html/canvas/CanvasStyle.cpp index 5352473..3515e03 100644 --- a/WebCore/html/canvas/CanvasStyle.cpp +++ b/WebCore/html/canvas/CanvasStyle.cpp @@ -173,22 +173,12 @@ void CanvasStyle::applyFillColor(GraphicsContext* context) return; switch (m_type) { case ColorString: { - Color c = Color(m_color); - if (c.isValid()) { - context->setFillColor(c.rgb(), DeviceColorSpace); - break; - } RGBA32 rgba = 0; // default is transparent black if (CSSParser::parseColor(rgba, m_color)) context->setFillColor(rgba, DeviceColorSpace); break; } case ColorStringWithAlpha: { - Color c = Color(m_color); - if (c.isValid()) { - context->setFillColor(colorWithOverrideAlpha(c.rgb(), m_alpha), DeviceColorSpace); - break; - } RGBA32 color = 0; // default is transparent black if (CSSParser::parseColor(color, m_color)) context->setFillColor(colorWithOverrideAlpha(color, m_alpha), DeviceColorSpace); diff --git a/WebCore/html/canvas/WebGLArray.cpp b/WebCore/html/canvas/WebGLArray.cpp index c5a712d..038aea4 100644 --- a/WebCore/html/canvas/WebGLArray.cpp +++ b/WebCore/html/canvas/WebGLArray.cpp @@ -46,13 +46,33 @@ WebGLArray::~WebGLArray() void WebGLArray::setImpl(WebGLArray* array, unsigned byteOffset, ExceptionCode& ec) { - if (byteOffset + array->byteLength() > byteLength()) { + if (byteOffset > byteLength() || + byteOffset + array->byteLength() > byteLength() || + byteOffset + array->byteLength() < byteOffset) { + // Out of range offset or overflow ec = INDEX_SIZE_ERR; return; } char* base = static_cast<char*>(baseAddress()); - memcpy(base + byteOffset, array->baseAddress(), array->byteLength()); + memmove(base + byteOffset, array->baseAddress(), array->byteLength()); +} + +void WebGLArray::calculateOffsetAndLength(int start, int end, unsigned arraySize, + unsigned* offset, unsigned* length) +{ + if (start < 0) + start += arraySize; + if (start < 0) + start = 0; + if (end < 0) + end += arraySize; + if (end < 0) + end = 0; + if (end < start) + end = start; + *offset = static_cast<unsigned>(start); + *length = static_cast<unsigned>(end - start); } } diff --git a/WebCore/html/canvas/WebGLArray.h b/WebCore/html/canvas/WebGLArray.h index 11065cc..7d67474 100644 --- a/WebCore/html/canvas/WebGLArray.h +++ b/WebCore/html/canvas/WebGLArray.h @@ -26,7 +26,9 @@ #ifndef WebGLArray_h #define WebGLArray_h +#include <algorithm> #include "ExceptionCode.h" +#include <limits.h> #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> #include <wtf/RefPtr.h> @@ -58,7 +60,7 @@ class WebGLArray : public RefCounted<WebGLArray> { virtual unsigned length() const = 0; virtual unsigned byteLength() const = 0; - virtual PassRefPtr<WebGLArray> slice(unsigned offset, unsigned length) = 0; + virtual PassRefPtr<WebGLArray> slice(int start, int end) = 0; virtual ~WebGLArray(); @@ -67,6 +69,48 @@ class WebGLArray : public RefCounted<WebGLArray> { void setImpl(WebGLArray* array, unsigned byteOffset, ExceptionCode& ec); + void calculateOffsetAndLength(int start, int end, unsigned arraySize, + unsigned* offset, unsigned* length); + + // Helper to verify that a given sub-range of an ArrayBuffer is + // within range. + template <typename T> + static bool verifySubRange(PassRefPtr<WebGLArrayBuffer> buffer, + unsigned byteOffset, + unsigned numElements) + { + if (!buffer) + return false; + if (sizeof(T) > 1 && byteOffset % sizeof(T)) + return false; + if (byteOffset > buffer->byteLength()) + return false; + unsigned remainingElements = (buffer->byteLength() - byteOffset) / sizeof(T); + if (numElements > remainingElements) + return false; + return true; + } + + // Input offset is in number of elements from this array's view; + // output offset is in number of bytes from the underlying buffer's view. + template <typename T> + static void clampOffsetAndNumElements(PassRefPtr<WebGLArrayBuffer> buffer, + unsigned arrayByteOffset, + unsigned *offset, + unsigned *numElements) + { + unsigned maxOffset = (UINT_MAX - arrayByteOffset) / sizeof(T); + if (*offset > maxOffset) { + *offset = buffer->byteLength(); + *numElements = 0; + return; + } + *offset = arrayByteOffset + *offset * sizeof(T); + *offset = std::min(buffer->byteLength(), *offset); + unsigned remainingElements = (buffer->byteLength() - *offset) / sizeof(T); + *numElements = std::min(remainingElements, *numElements); + } + // This is the address of the WebGLArrayBuffer's storage, plus the byte offset. void* m_baseAddress; diff --git a/WebCore/html/canvas/WebGLArray.idl b/WebCore/html/canvas/WebGLArray.idl index 02e1f51..2cc00d0 100644 --- a/WebCore/html/canvas/WebGLArray.idl +++ b/WebCore/html/canvas/WebGLArray.idl @@ -30,6 +30,6 @@ module html { readonly attribute unsigned long byteLength; readonly attribute unsigned long length; - WebGLArray slice(in unsigned long offset, in unsigned long length); + [Custom] WebGLArray slice(in long start, in long end); }; } diff --git a/WebCore/html/canvas/WebGLArrayBuffer.cpp b/WebCore/html/canvas/WebGLArrayBuffer.cpp index c565691..7d3cd33 100644 --- a/WebCore/html/canvas/WebGLArrayBuffer.cpp +++ b/WebCore/html/canvas/WebGLArrayBuffer.cpp @@ -33,21 +33,27 @@ namespace WebCore { -PassRefPtr<WebGLArrayBuffer> WebGLArrayBuffer::create(unsigned sizeInBytes) +PassRefPtr<WebGLArrayBuffer> WebGLArrayBuffer::create(unsigned numElements, unsigned elementByteSize) { - return adoptRef(new WebGLArrayBuffer(sizeInBytes)); + void* data = tryAllocate(numElements, elementByteSize); + if (!data) + return 0; + return adoptRef(new WebGLArrayBuffer(data, numElements * elementByteSize)); } PassRefPtr<WebGLArrayBuffer> WebGLArrayBuffer::create(WebGLArrayBuffer* other) { - RefPtr<WebGLArrayBuffer> buffer = adoptRef(new WebGLArrayBuffer(other->byteLength())); + void* data = tryAllocate(other->byteLength(), 1); + if (!data) + return 0; + RefPtr<WebGLArrayBuffer> buffer = adoptRef(new WebGLArrayBuffer(data, other->byteLength())); memcpy(buffer->data(), other->data(), other->byteLength()); return buffer.release(); } -WebGLArrayBuffer::WebGLArrayBuffer(unsigned sizeInBytes) { - m_sizeInBytes = sizeInBytes; - m_data = WTF::fastZeroedMalloc(sizeInBytes); +WebGLArrayBuffer::WebGLArrayBuffer(void* data, unsigned sizeInBytes) + : m_sizeInBytes(sizeInBytes) + , m_data(data) { } void* WebGLArrayBuffer::data() { @@ -66,6 +72,19 @@ WebGLArrayBuffer::~WebGLArrayBuffer() { WTF::fastFree(m_data); } +void* WebGLArrayBuffer::tryAllocate(unsigned numElements, unsigned elementByteSize) { + void* result; + // Do not allow 32-bit overflow of the total size + if (numElements) { + unsigned totalSize = numElements * elementByteSize; + if (totalSize / numElements != elementByteSize) + return 0; + } + if (WTF::tryFastCalloc(numElements, elementByteSize).getValue(result)) + return result; + return 0; +} + } #endif // ENABLE(3D_CANVAS) diff --git a/WebCore/html/canvas/WebGLArrayBuffer.h b/WebCore/html/canvas/WebGLArrayBuffer.h index a076e16..59e0ddd 100644 --- a/WebCore/html/canvas/WebGLArrayBuffer.h +++ b/WebCore/html/canvas/WebGLArrayBuffer.h @@ -33,7 +33,7 @@ namespace WebCore { class WebGLArrayBuffer : public RefCounted<WebGLArrayBuffer> { public: - static PassRefPtr<WebGLArrayBuffer> create(unsigned sizeInBytes); + static PassRefPtr<WebGLArrayBuffer> create(unsigned numElements, unsigned elementByteSize); static PassRefPtr<WebGLArrayBuffer> create(WebGLArrayBuffer*); void* data(); @@ -43,7 +43,9 @@ class WebGLArrayBuffer : public RefCounted<WebGLArrayBuffer> { ~WebGLArrayBuffer(); private: - WebGLArrayBuffer(unsigned sizeInBytes); + WebGLArrayBuffer(void* data, unsigned sizeInBytes); + WebGLArrayBuffer(unsigned numElements, unsigned elementByteSize); + static void* tryAllocate(unsigned numElements, unsigned elementByteSize); unsigned m_sizeInBytes; void* m_data; }; diff --git a/WebCore/html/canvas/WebGLByteArray.cpp b/WebCore/html/canvas/WebGLByteArray.cpp index 1c2849b..603e4d1 100644 --- a/WebCore/html/canvas/WebGLByteArray.cpp +++ b/WebCore/html/canvas/WebGLByteArray.cpp @@ -35,7 +35,7 @@ namespace WebCore { PassRefPtr<WebGLByteArray> WebGLByteArray::create(unsigned length) { - RefPtr<WebGLArrayBuffer> buffer = WebGLArrayBuffer::create(length * sizeof(signed char)); + RefPtr<WebGLArrayBuffer> buffer = WebGLArrayBuffer::create(length, sizeof(signed char)); return create(buffer, 0, length); } @@ -47,19 +47,16 @@ PassRefPtr<WebGLByteArray> WebGLByteArray::create(signed char* array, unsigned l return a; } -PassRefPtr<WebGLByteArray> WebGLByteArray::create(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length) +PassRefPtr<WebGLByteArray> WebGLByteArray::create(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length) { - if (buffer) { - // Check to make sure we are talking about a valid region of - // the given WebGLArrayBuffer's storage. - if ((byteOffset + (length * sizeof(signed char))) > buffer->byteLength()) - return NULL; - } + RefPtr<WebGLArrayBuffer> buf(buffer); + if (!verifySubRange<signed char>(buf, byteOffset, length)) + return 0; - return adoptRef(new WebGLByteArray(buffer, byteOffset, length)); + return adoptRef(new WebGLByteArray(buf, byteOffset, length)); } -WebGLByteArray::WebGLByteArray(PassRefPtr<WebGLArrayBuffer> buffer, int offset, unsigned length) +WebGLByteArray::WebGLByteArray(PassRefPtr<WebGLArrayBuffer> buffer, unsigned offset, unsigned length) : WebGLArray(buffer, offset) , m_size(length) { @@ -73,15 +70,12 @@ unsigned WebGLByteArray::byteLength() const { return m_size * sizeof(signed char); } -PassRefPtr<WebGLArray> WebGLByteArray::slice(unsigned offset, unsigned length) { - // Check to make sure the specified region is within the bounds of - // the WebGLArrayBuffer. - unsigned startByte = m_byteOffset + offset * sizeof(signed char); - unsigned limitByte = startByte + length * sizeof(signed char); - unsigned bufferLength = buffer()->byteLength(); - if (startByte >= bufferLength || limitByte > bufferLength) - return 0; - return create(buffer(), startByte, length); +PassRefPtr<WebGLArray> WebGLByteArray::slice(int start, int end) +{ + unsigned offset, length; + calculateOffsetAndLength(start, end, m_size, &offset, &length); + clampOffsetAndNumElements<signed char>(buffer().get(), m_byteOffset, &offset, &length); + return create(buffer(), offset, length); } void WebGLByteArray::set(WebGLByteArray* array, unsigned offset, ExceptionCode& ec) { diff --git a/WebCore/html/canvas/WebGLByteArray.h b/WebCore/html/canvas/WebGLByteArray.h index c517c03..60d301c 100644 --- a/WebCore/html/canvas/WebGLByteArray.h +++ b/WebCore/html/canvas/WebGLByteArray.h @@ -43,13 +43,13 @@ class WebGLByteArray : public WebGLArray { static PassRefPtr<WebGLByteArray> create(unsigned length); static PassRefPtr<WebGLByteArray> create(signed char* array, unsigned length); - static PassRefPtr<WebGLByteArray> create(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length); + static PassRefPtr<WebGLByteArray> create(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length); char* data() { return static_cast<char*>(baseAddress()); } virtual unsigned length() const; virtual unsigned byteLength() const; - virtual PassRefPtr<WebGLArray> slice(unsigned offset, unsigned length); + virtual PassRefPtr<WebGLArray> slice(int start, int end); void set(unsigned index, double value) { @@ -90,7 +90,7 @@ class WebGLByteArray : public WebGLArray { private: WebGLByteArray(PassRefPtr<WebGLArrayBuffer> buffer, - int offset, + unsigned offset, unsigned length); unsigned m_size; }; diff --git a/WebCore/html/canvas/WebGLFloatArray.cpp b/WebCore/html/canvas/WebGLFloatArray.cpp index 6192898..ca93c4c 100644 --- a/WebCore/html/canvas/WebGLFloatArray.cpp +++ b/WebCore/html/canvas/WebGLFloatArray.cpp @@ -34,7 +34,7 @@ namespace WebCore { PassRefPtr<WebGLFloatArray> WebGLFloatArray::create(unsigned length) { - RefPtr<WebGLArrayBuffer> buffer = WebGLArrayBuffer::create(length * sizeof(float)); + RefPtr<WebGLArrayBuffer> buffer = WebGLArrayBuffer::create(length, sizeof(float)); return create(buffer, 0, length); } @@ -46,22 +46,16 @@ PassRefPtr<WebGLFloatArray> WebGLFloatArray::create(float* array, unsigned lengt return a; } -PassRefPtr<WebGLFloatArray> WebGLFloatArray::create(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length) +PassRefPtr<WebGLFloatArray> WebGLFloatArray::create(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length) { - // Make sure the offset results in valid alignment. - if ((byteOffset % sizeof(float)) != 0) - return NULL; + RefPtr<WebGLArrayBuffer> buf(buffer); + if (!verifySubRange<float>(buf, byteOffset, length)) + return 0; - if (buffer) { - // Check to make sure we are talking about a valid region of - // the given WebGLArrayBuffer's storage. - if ((byteOffset + (length * sizeof(float))) > buffer->byteLength()) - return NULL; - } - return adoptRef(new WebGLFloatArray(buffer, byteOffset, length)); + return adoptRef(new WebGLFloatArray(buf, byteOffset, length)); } -WebGLFloatArray::WebGLFloatArray(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length) +WebGLFloatArray::WebGLFloatArray(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length) : WebGLArray(buffer, byteOffset) , m_size(length) { @@ -75,15 +69,12 @@ unsigned WebGLFloatArray::byteLength() const { return m_size * sizeof(float); } -PassRefPtr<WebGLArray> WebGLFloatArray::slice(unsigned offset, unsigned length) { - // Check to make sure the specified region is within the bounds of - // the WebGLArrayBuffer. - unsigned startByte = m_byteOffset + offset * sizeof(float); - unsigned limitByte = startByte + length * sizeof(float); - unsigned bufferLength = buffer()->byteLength(); - if (startByte >= bufferLength || limitByte > bufferLength) - return 0; - return create(buffer(), startByte, length); +PassRefPtr<WebGLArray> WebGLFloatArray::slice(int start, int end) +{ + unsigned offset, length; + calculateOffsetAndLength(start, end, m_size, &offset, &length); + clampOffsetAndNumElements<float>(buffer(), m_byteOffset, &offset, &length); + return create(buffer(), offset, length); } void WebGLFloatArray::set(WebGLFloatArray* array, unsigned offset, ExceptionCode& ec) { diff --git a/WebCore/html/canvas/WebGLFloatArray.h b/WebCore/html/canvas/WebGLFloatArray.h index 4607962..5b4e6c9 100644 --- a/WebCore/html/canvas/WebGLFloatArray.h +++ b/WebCore/html/canvas/WebGLFloatArray.h @@ -40,13 +40,13 @@ class WebGLFloatArray : public WebGLArray { static PassRefPtr<WebGLFloatArray> create(unsigned length); static PassRefPtr<WebGLFloatArray> create(float* array, unsigned length); - static PassRefPtr<WebGLFloatArray> create(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length); + static PassRefPtr<WebGLFloatArray> create(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length); float* data() { return static_cast<float*>(baseAddress()); } virtual unsigned length() const; virtual unsigned byteLength() const; - virtual PassRefPtr<WebGLArray> slice(unsigned offset, unsigned length); + virtual PassRefPtr<WebGLArray> slice(int start, int end); void set(unsigned index, double value) { @@ -86,7 +86,7 @@ class WebGLFloatArray : public WebGLArray { void set(WebGLFloatArray* array, unsigned offset, ExceptionCode& ec); private: - WebGLFloatArray(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length); + WebGLFloatArray(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length); unsigned m_size; }; diff --git a/WebCore/html/canvas/WebGLFramebuffer.cpp b/WebCore/html/canvas/WebGLFramebuffer.cpp index 7ade990..614437b 100644 --- a/WebCore/html/canvas/WebGLFramebuffer.cpp +++ b/WebCore/html/canvas/WebGLFramebuffer.cpp @@ -39,10 +39,28 @@ PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContext* ctx WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContext* ctx) : CanvasObject(ctx) + , m_isDepthAttached(false) + , m_isStencilAttached(false) + , m_isDepthStencilAttached(false) { setObject(context()->graphicsContext3D()->createFramebuffer()); } +void WebGLFramebuffer::setIsAttached(unsigned long attachment, bool isAttached) +{ + switch (attachment) { + case GraphicsContext3D::DEPTH_ATTACHMENT: + m_isDepthAttached = isAttached; + break; + case GraphicsContext3D::STENCIL_ATTACHMENT: + m_isStencilAttached = isAttached; + break; + case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT: + m_isDepthStencilAttached = isAttached; + break; + } +} + void WebGLFramebuffer::_deleteObject(Platform3DObject object) { context()->graphicsContext3D()->deleteFramebuffer(object); diff --git a/WebCore/html/canvas/WebGLFramebuffer.h b/WebCore/html/canvas/WebGLFramebuffer.h index 10b6772..b9402a0 100644 --- a/WebCore/html/canvas/WebGLFramebuffer.h +++ b/WebCore/html/canvas/WebGLFramebuffer.h @@ -39,10 +39,21 @@ namespace WebCore { static PassRefPtr<WebGLFramebuffer> create(WebGLRenderingContext*); + void setIsAttached(unsigned long attachment, bool isAttached); + + bool isDepthAttached() const { return m_isDepthAttached; } + bool isStencilAttached() const { return m_isStencilAttached; } + bool isDepthStencilAttached() const { return m_isDepthStencilAttached; } + protected: WebGLFramebuffer(WebGLRenderingContext*); virtual void _deleteObject(Platform3DObject); + + private: + bool m_isDepthAttached; + bool m_isStencilAttached; + bool m_isDepthStencilAttached; }; } // namespace WebCore diff --git a/WebCore/html/canvas/WebGLIntArray.cpp b/WebCore/html/canvas/WebGLIntArray.cpp index 4617010..21b7a88 100644 --- a/WebCore/html/canvas/WebGLIntArray.cpp +++ b/WebCore/html/canvas/WebGLIntArray.cpp @@ -35,7 +35,7 @@ namespace WebCore { PassRefPtr<WebGLIntArray> WebGLIntArray::create(unsigned length) { - RefPtr<WebGLArrayBuffer> buffer = WebGLArrayBuffer::create(length * sizeof(int)); + RefPtr<WebGLArrayBuffer> buffer = WebGLArrayBuffer::create(length, sizeof(int)); return create(buffer, 0, length); } @@ -48,24 +48,17 @@ PassRefPtr<WebGLIntArray> WebGLIntArray::create(int* array, unsigned length) } PassRefPtr<WebGLIntArray> WebGLIntArray::create(PassRefPtr<WebGLArrayBuffer> buffer, - int byteOffset, + unsigned byteOffset, unsigned length) { - // Make sure the offset results in valid alignment. - if ((byteOffset % sizeof(int)) != 0) - return NULL; - - if (buffer) { - // Check to make sure we are talking about a valid region of - // the given WebGLArrayBuffer's storage. - if ((byteOffset + (length * sizeof(int))) > buffer->byteLength()) - return NULL; - } + RefPtr<WebGLArrayBuffer> buf(buffer); + if (!verifySubRange<int>(buf, byteOffset, length)) + return 0; - return adoptRef(new WebGLIntArray(buffer, byteOffset, length)); + return adoptRef(new WebGLIntArray(buf, byteOffset, length)); } -WebGLIntArray::WebGLIntArray(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length) +WebGLIntArray::WebGLIntArray(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length) : WebGLArray(buffer, byteOffset) , m_size(length) { @@ -79,15 +72,12 @@ unsigned WebGLIntArray::byteLength() const { return m_size * sizeof(int); } -PassRefPtr<WebGLArray> WebGLIntArray::slice(unsigned offset, unsigned length) { - // Check to make sure the specified region is within the bounds of - // the WebGLArrayBuffer. - unsigned startByte = m_byteOffset + offset * sizeof(int); - unsigned limitByte = startByte + length * sizeof(int); - unsigned bufferLength = buffer()->byteLength(); - if (startByte >= bufferLength || limitByte > bufferLength) - return 0; - return create(buffer(), startByte, length); +PassRefPtr<WebGLArray> WebGLIntArray::slice(int start, int end) +{ + unsigned offset, length; + calculateOffsetAndLength(start, end, m_size, &offset, &length); + clampOffsetAndNumElements<int>(buffer(), m_byteOffset, &offset, &length); + return create(buffer(), offset, length); } void WebGLIntArray::set(WebGLIntArray* array, unsigned offset, ExceptionCode& ec) { diff --git a/WebCore/html/canvas/WebGLIntArray.h b/WebCore/html/canvas/WebGLIntArray.h index 25108ac..5929e75 100644 --- a/WebCore/html/canvas/WebGLIntArray.h +++ b/WebCore/html/canvas/WebGLIntArray.h @@ -41,13 +41,13 @@ class WebGLIntArray : public WebGLArray { static PassRefPtr<WebGLIntArray> create(unsigned length); static PassRefPtr<WebGLIntArray> create(int* array, unsigned length); - static PassRefPtr<WebGLIntArray> create(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length); + static PassRefPtr<WebGLIntArray> create(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length); int* data() { return static_cast<int*>(baseAddress()); } virtual unsigned length() const; virtual unsigned byteLength() const; - virtual PassRefPtr<WebGLArray> slice(unsigned offset, unsigned length); + virtual PassRefPtr<WebGLArray> slice(int start, int end); void set(unsigned index, double value) { @@ -87,7 +87,7 @@ class WebGLIntArray : public WebGLArray { private: WebGLIntArray(PassRefPtr<WebGLArrayBuffer> buffer, - int byteOffset, + unsigned byteOffset, unsigned length); unsigned m_size; }; diff --git a/WebCore/html/canvas/WebGLProgram.cpp b/WebCore/html/canvas/WebGLProgram.cpp index c2606c1..750df45 100644 --- a/WebCore/html/canvas/WebGLProgram.cpp +++ b/WebCore/html/canvas/WebGLProgram.cpp @@ -48,6 +48,41 @@ void WebGLProgram::_deleteObject(Platform3DObject object) context()->graphicsContext3D()->deleteProgram(object); } +bool WebGLProgram::cacheActiveAttribLocations() +{ + m_activeAttribLocations.clear(); + if (!object()) + return false; + GraphicsContext3D* context3d = context()->graphicsContext3D(); + int linkStatus; + context3d->getProgramiv(this, GraphicsContext3D::LINK_STATUS, &linkStatus); + if (!linkStatus) + return false; + + int numAttribs = 0; + context3d->getProgramiv(this, GraphicsContext3D::ACTIVE_ATTRIBUTES, &numAttribs); + m_activeAttribLocations.resize(static_cast<size_t>(numAttribs)); + for (int i = 0; i < numAttribs; ++i) { + ActiveInfo info; + context3d->getActiveAttrib(this, i, info); + m_activeAttribLocations[i] = context3d->getAttribLocation(this, info.name.charactersWithNullTermination()); + } + + return true; +} + +int WebGLProgram::numActiveAttribLocations() +{ + return static_cast<int>(m_activeAttribLocations.size()); +} + +int WebGLProgram::getActiveAttribLocation(int index) +{ + if (index < 0 || index >= numActiveAttribLocations()) + return -1; + return m_activeAttribLocations[static_cast<size_t>(index)]; +} + } #endif // ENABLE(3D_CANVAS) diff --git a/WebCore/html/canvas/WebGLProgram.h b/WebCore/html/canvas/WebGLProgram.h index 8804d39..56bce15 100644 --- a/WebCore/html/canvas/WebGLProgram.h +++ b/WebCore/html/canvas/WebGLProgram.h @@ -30,6 +30,7 @@ #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> +#include <wtf/Vector.h> namespace WebCore { @@ -38,11 +39,20 @@ namespace WebCore { virtual ~WebGLProgram() { deleteObject(); } static PassRefPtr<WebGLProgram> create(WebGLRenderingContext*); + + // cacheActiveAttribLocation() is only called once after linkProgram() + // succeeds. + bool cacheActiveAttribLocations(); + int numActiveAttribLocations(); + int getActiveAttribLocation(int index); protected: WebGLProgram(WebGLRenderingContext*); virtual void _deleteObject(Platform3DObject); + + private: + Vector<int> m_activeAttribLocations; }; } // namespace WebCore diff --git a/WebCore/html/canvas/WebGLRenderbuffer.cpp b/WebCore/html/canvas/WebGLRenderbuffer.cpp index 286ad2e..cad4298 100644 --- a/WebCore/html/canvas/WebGLRenderbuffer.cpp +++ b/WebCore/html/canvas/WebGLRenderbuffer.cpp @@ -44,12 +44,14 @@ PassRefPtr<WebGLRenderbuffer> WebGLRenderbuffer::create(WebGLRenderingContext* c WebGLRenderbuffer::WebGLRenderbuffer(WebGLRenderingContext* ctx) : CanvasObject(ctx) + , m_internalformat(GraphicsContext3D::RGBA4) { setObject(context()->graphicsContext3D()->createRenderbuffer()); } WebGLRenderbuffer::WebGLRenderbuffer(WebGLRenderingContext* ctx, Platform3DObject obj) : CanvasObject(ctx) + , m_internalformat(GraphicsContext3D::RGBA4) { setObject(obj, false); } diff --git a/WebCore/html/canvas/WebGLRenderbuffer.h b/WebCore/html/canvas/WebGLRenderbuffer.h index 790fdcd..1bdf1b7 100644 --- a/WebCore/html/canvas/WebGLRenderbuffer.h +++ b/WebCore/html/canvas/WebGLRenderbuffer.h @@ -43,11 +43,17 @@ namespace WebCore { // FIXME: should consider canonicalizing these objects static PassRefPtr<WebGLRenderbuffer> create(WebGLRenderingContext*, Platform3DObject renderbuffer); + void setInternalformat(unsigned long internalformat) { m_internalformat = internalformat; } + unsigned long getInternalformat() const { return m_internalformat; } + protected: WebGLRenderbuffer(WebGLRenderingContext*); WebGLRenderbuffer(WebGLRenderingContext*, Platform3DObject); virtual void _deleteObject(Platform3DObject); + + private: + unsigned long m_internalformat; }; } // namespace WebCore diff --git a/WebCore/html/canvas/WebGLRenderingContext.cpp b/WebCore/html/canvas/WebGLRenderingContext.cpp index 6cb3348..d9af757 100644 --- a/WebCore/html/canvas/WebGLRenderingContext.cpp +++ b/WebCore/html/canvas/WebGLRenderingContext.cpp @@ -30,6 +30,7 @@ #include "WebGLRenderingContext.h" #include "CanvasPixelArray.h" +#include "FrameView.h" #include "HTMLCanvasElement.h" #include "HTMLImageElement.h" #include "ImageBuffer.h" @@ -38,6 +39,7 @@ #include "RenderBox.h" #include "RenderLayer.h" #include "WebGLActiveInfo.h" +#include "WebGLUnsignedShortArray.h" #include "WebGLBuffer.h" #include "WebGLContextAttributes.h" #include "WebGLFramebuffer.h" @@ -46,12 +48,6 @@ #include "WebGLTexture.h" #include "WebGLShader.h" #include "WebGLUniformLocation.h" -#include "HTMLCanvasElement.h" -#include "HTMLImageElement.h" -#include "ImageBuffer.h" -#include "NotImplemented.h" -#include "RenderBox.h" -#include "RenderLayer.h" #include <wtf/ByteArray.h> @@ -78,7 +74,9 @@ private: PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElement* canvas, WebGLContextAttributes* attrs) { - OwnPtr<GraphicsContext3D> context(GraphicsContext3D::create(attrs->attributes())); + HostWindow* hostWindow = canvas->document()->view()->root()->hostWindow(); + OwnPtr<GraphicsContext3D> context(GraphicsContext3D::create(attrs->attributes(), hostWindow)); + if (!context) return 0; @@ -91,12 +89,23 @@ WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, Pa , m_needsUpdate(true) , m_markedCanvasDirty(false) , m_activeTextureUnit(0) + , m_packAlignment(4) + , m_unpackAlignment(4) { ASSERT(m_context); int numVertexAttribs = 0; m_context->getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &numVertexAttribs); m_maxVertexAttribs = numVertexAttribs; + int implementationColorReadFormat = GraphicsContext3D::RGBA; + m_context->getIntegerv(GraphicsContext3D::IMPLEMENTATION_COLOR_READ_FORMAT, &implementationColorReadFormat); + m_implementationColorReadFormat = implementationColorReadFormat; + int implementationColorReadType = GraphicsContext3D::UNSIGNED_BYTE; + m_context->getIntegerv(GraphicsContext3D::IMPLEMENTATION_COLOR_READ_TYPE, &implementationColorReadType); + // FIXME: remove the getError() when IMPLEMENTATION_COLOR_READ_FORMAT/TYPE are supported. + m_context->getError(); + m_implementationColorReadType = implementationColorReadType; m_context->reshape(canvas()->width(), canvas()->height()); + m_context->viewport(0, 0, canvas()->width(), canvas()->height()); } WebGLRenderingContext::~WebGLRenderingContext() @@ -107,9 +116,10 @@ WebGLRenderingContext::~WebGLRenderingContext() void WebGLRenderingContext::markContextChanged() { #if USE(ACCELERATED_COMPOSITING) - if (canvas()->renderBox() && canvas()->renderBox()->hasLayer()) { - canvas()->renderBox()->layer()->rendererContentChanged(); - } else { + RenderBox* renderBox = canvas()->renderBox(); + if (renderBox && renderBox->hasLayer() && renderBox->layer()->hasAcceleratedCompositing()) + renderBox->layer()->rendererContentChanged(); + else { #endif if (!m_markedCanvasDirty) { // Make sure the canvas's image buffer is allocated. @@ -141,8 +151,9 @@ void WebGLRenderingContext::reshape(int width, int height) { if (m_needsUpdate) { #if USE(ACCELERATED_COMPOSITING) - if (canvas()->renderBox() && canvas()->renderBox()->hasLayer()) - canvas()->renderBox()->layer()->rendererContentChanged(); + RenderBox* renderBox = canvas()->renderBox(); + if (renderBox && renderBox->hasLayer()) + renderBox->layer()->rendererContentChanged(); #endif m_needsUpdate = false; } @@ -186,10 +197,8 @@ void WebGLRenderingContext::attachShader(WebGLProgram* program, WebGLShader* sha void WebGLRenderingContext::bindAttribLocation(WebGLProgram* program, unsigned long index, const String& name, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!program || program->context() != this) { - m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + if (!validateWebGLObject(program)) return; - } m_context->bindAttribLocation(program, index, name); cleanupAfterGraphicsCall(false); } @@ -412,10 +421,8 @@ void WebGLRenderingContext::colorMask(bool red, bool green, bool blue, bool alph void WebGLRenderingContext::compileShader(WebGLShader* shader, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!shader || shader->context() != this) { - m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + if (!validateWebGLObject(shader)) return; - } m_context->compileShader(shader); cleanupAfterGraphicsCall(false); } @@ -555,10 +562,8 @@ void WebGLRenderingContext::depthRange(double zNear, double zFar) void WebGLRenderingContext::detachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!program || program->context() != this || !shader || shader->context() != this) { - m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + if (!validateWebGLObject(program) || !validateWebGLObject(shader)) return; - } m_context->detachShader(program, shader); cleanupAfterGraphicsCall(false); } @@ -691,12 +696,20 @@ bool WebGLRenderingContext::validateIndexArrayPrecise(unsigned long count, unsig bool WebGLRenderingContext::validateRenderingState(long numElementsRequired) { + if (!m_currentProgram) + return false; + // Look in each enabled vertex attrib and find the smallest buffer size long smallestNumElements = LONG_MAX; - for (unsigned i = 0; i < m_vertexAttribState.size(); ++i) { - const VertexAttribState& state = m_vertexAttribState[i]; - if (state.enabled && state.numElements < smallestNumElements) - smallestNumElements = state.numElements; + int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations(); + int numAttribStates = static_cast<int>(m_vertexAttribState.size()); + for (int i = 0; i < numActiveAttribLocations; ++i) { + int loc = m_currentProgram->getActiveAttribLocation(i); + if (loc >=0 && loc < numAttribStates) { + const VertexAttribState& state = m_vertexAttribState[loc]; + if (state.enabled && state.numElements < smallestNumElements) + smallestNumElements = state.numElements; + } } if (smallestNumElements == LONG_MAX) @@ -705,6 +718,19 @@ bool WebGLRenderingContext::validateRenderingState(long numElementsRequired) return numElementsRequired <= smallestNumElements; } +bool WebGLRenderingContext::validateWebGLObject(CanvasObject* object) +{ + if (!object) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return false; + } + if (object->context() != this) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + return false; + } + return true; +} + void WebGLRenderingContext::drawArrays(unsigned long mode, long first, long count, ExceptionCode& ec) { UNUSED_PARAM(ec); @@ -789,6 +815,45 @@ void WebGLRenderingContext::framebufferRenderbuffer(unsigned long target, unsign m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } + if (buffer->object()) { + bool isConflicted = false; + bool isDepthOrStencil = true; + switch (attachment) { + case GraphicsContext3D::DEPTH_ATTACHMENT: + if (m_framebufferBinding->isDepthStencilAttached() || m_framebufferBinding->isStencilAttached()) + isConflicted = true; + if (buffer->getInternalformat() != GraphicsContext3D::DEPTH_COMPONENT16) + isConflicted = true; + break; + case GraphicsContext3D::STENCIL_ATTACHMENT: + if (m_framebufferBinding->isDepthStencilAttached() || m_framebufferBinding->isDepthAttached()) + isConflicted = true; + if (buffer->getInternalformat() != GraphicsContext3D::STENCIL_INDEX8) + isConflicted = true; + break; + case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT: + if (m_framebufferBinding->isDepthAttached() || m_framebufferBinding->isStencilAttached()) + isConflicted = true; + if (buffer->getInternalformat() != GraphicsContext3D::DEPTH_STENCIL) + isConflicted = true; + break; + default: + isDepthOrStencil = false; + } + if (isConflicted) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + return; + } + if (isDepthOrStencil) + m_framebufferBinding->setIsAttached(attachment, true); + } else { // Detach + switch (attachment) { + case GraphicsContext3D::DEPTH_ATTACHMENT: + case GraphicsContext3D::STENCIL_ATTACHMENT: + case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT: + m_framebufferBinding->setIsAttached(attachment, false); + } + } m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, buffer); cleanupAfterGraphicsCall(false); } @@ -827,10 +892,8 @@ PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveAttrib(WebGLProgram* { UNUSED_PARAM(ec); ActiveInfo info; - if (!program || program->context() != this) { - m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + if (!validateWebGLObject(program)) return 0; - } if (!m_context->getActiveAttrib(program, index, info)) { return 0; } @@ -841,10 +904,8 @@ PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveUniform(WebGLProgram { UNUSED_PARAM(ec); ActiveInfo info; - if (!program || program->context() != this) { - m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + if (!validateWebGLObject(program)) return 0; - } if (!m_context->getActiveUniform(program, index, info)) { return 0; } @@ -896,7 +957,8 @@ WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(unsigned l if (target != GraphicsContext3D::FRAMEBUFFER || (attachment != GraphicsContext3D::COLOR_ATTACHMENT0 && attachment != GraphicsContext3D::DEPTH_ATTACHMENT - && attachment != GraphicsContext3D::STENCIL_ATTACHMENT) + && attachment != GraphicsContext3D::STENCIL_ATTACHMENT + && attachment != GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT) || (pname != GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE && pname != GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME && pname != GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL @@ -1115,10 +1177,8 @@ WebGLGetInfo WebGLRenderingContext::getParameter(unsigned long pname, ExceptionC WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, unsigned long pname, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!program || program->context() != this) { - m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + if (!validateWebGLObject(program)) return WebGLGetInfo(); - } WebGLStateRestorer(this, false); int value = 0; @@ -1145,10 +1205,8 @@ WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, u String WebGLRenderingContext::getProgramInfoLog(WebGLProgram* program, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!program || program->context() != this) { - m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + if (!validateWebGLObject(program)) return ""; - } WebGLStateRestorer(this, false); return m_context->getProgramInfoLog(program); } @@ -1175,8 +1233,11 @@ WebGLGetInfo WebGLRenderingContext::getRenderbufferParameter(unsigned long targe m_context->getRenderbufferParameteriv(target, pname, &value); return WebGLGetInfo(static_cast<long>(value)); case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT: - m_context->getRenderbufferParameteriv(target, pname, &value); - return WebGLGetInfo(static_cast<unsigned long>(value)); + if (!m_renderbufferBinding) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + return WebGLGetInfo(); + } + return WebGLGetInfo(m_renderbufferBinding->getInternalformat()); default: m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); return WebGLGetInfo(); @@ -1186,10 +1247,8 @@ WebGLGetInfo WebGLRenderingContext::getRenderbufferParameter(unsigned long targe WebGLGetInfo WebGLRenderingContext::getShaderParameter(WebGLShader* shader, unsigned long pname, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!shader || shader->context() != this) { - m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + if (!validateWebGLObject(shader)) return WebGLGetInfo(); - } WebGLStateRestorer(this, false); int value = 0; switch (pname) { @@ -1213,10 +1272,8 @@ WebGLGetInfo WebGLRenderingContext::getShaderParameter(WebGLShader* shader, unsi String WebGLRenderingContext::getShaderInfoLog(WebGLShader* shader, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!shader || shader->context() != this) { - m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + if (!validateWebGLObject(shader)) return ""; - } WebGLStateRestorer(this, false); return m_context->getShaderInfoLog(shader); } @@ -1224,10 +1281,8 @@ String WebGLRenderingContext::getShaderInfoLog(WebGLShader* shader, ExceptionCod String WebGLRenderingContext::getShaderSource(WebGLShader* shader, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!shader || shader->context() != this) { - m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + if (!validateWebGLObject(shader)) return ""; - } WebGLStateRestorer(this, false); return m_context->getShaderSource(shader); } @@ -1264,7 +1319,9 @@ WebGLGetInfo WebGLRenderingContext::getTexParameter(unsigned long target, unsign WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!program || uniformLocation->program() != program || program->context() != this) { + if (!validateWebGLObject(program)) + return WebGLGetInfo(); + if (uniformLocation->program() != program) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return WebGLGetInfo(); } @@ -1393,12 +1450,13 @@ WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebG PassRefPtr<WebGLUniformLocation> WebGLRenderingContext::getUniformLocation(WebGLProgram* program, const String& name, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!program || program->context() != this) { - m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + if (!validateWebGLObject(program)) return 0; - } WebGLStateRestorer(this, false); - return WebGLUniformLocation::create(program, m_context->getUniformLocation(program, name)); + long uniformLocation = m_context->getUniformLocation(program, name); + if (uniformLocation == -1) + return 0; + return WebGLUniformLocation::create(program, uniformLocation); } WebGLGetInfo WebGLRenderingContext::getVertexAttrib(unsigned long index, unsigned long pname, ExceptionCode& ec) @@ -1519,18 +1577,26 @@ void WebGLRenderingContext::lineWidth(double width) void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!program || program->context() != this) { - m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + if (!validateWebGLObject(program)) return; - } - m_context->linkProgram(program); + program->cacheActiveAttribLocations(); cleanupAfterGraphicsCall(false); } void WebGLRenderingContext::pixelStorei(unsigned long pname, long param) { m_context->pixelStorei(pname, param); + if (param == 1 || param == 2 || param == 4 || param == 8) { + switch (pname) { + case GraphicsContext3D::PACK_ALIGNMENT: + m_packAlignment = static_cast<int>(param); + break; + case GraphicsContext3D::UNPACK_ALIGNMENT: + m_unpackAlignment = static_cast<int>(param); + break; + } + } cleanupAfterGraphicsCall(false); } @@ -1542,7 +1608,76 @@ void WebGLRenderingContext::polygonOffset(double factor, double units) PassRefPtr<WebGLArray> WebGLRenderingContext::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type) { - RefPtr<WebGLArray> array = m_context->readPixels(x, y, width, height, format, type); + // Validate enums. + unsigned long componentsPerPixel = 0; + switch (format) { + case GraphicsContext3D::ALPHA: + componentsPerPixel = 1; + break; + case GraphicsContext3D::RGB: + componentsPerPixel = 3; + break; + case GraphicsContext3D::RGBA: + componentsPerPixel = 4; + break; + default: + m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); + return 0; + } + unsigned long bytesPerComponent = 0; + switch (type) { + case GraphicsContext3D::UNSIGNED_BYTE: + bytesPerComponent = sizeof(unsigned char); + break; + case GraphicsContext3D::UNSIGNED_SHORT_5_6_5: + case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4: + case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1: + componentsPerPixel = 1; + bytesPerComponent = sizeof(unsigned short); + break; + default: + m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); + return 0; + } + if (!(format == GraphicsContext3D::RGBA && type == GraphicsContext3D::UNSIGNED_BYTE || format == m_implementationColorReadFormat && type == m_implementationColorReadFormat)) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + return 0; + } + // Calculate array size, taking into consideration of PACK_ALIGNMENT. + unsigned long bytesPerRow = componentsPerPixel * bytesPerComponent * width; + unsigned long padding = 0; + unsigned long residualBytes = bytesPerRow % m_packAlignment; + if (residualBytes) { + padding = m_packAlignment - residualBytes; + bytesPerRow += padding; + } + // The last row needs no padding. + unsigned long totalBytes = bytesPerRow * height - padding; + unsigned long num = totalBytes / bytesPerComponent; + RefPtr<WebGLArray> array; + if (type == GraphicsContext3D::UNSIGNED_BYTE) + array = WebGLUnsignedByteArray::create(num); + else + array = WebGLUnsignedShortArray::create(num); + void* data = array->baseAddress(); + m_context->readPixels(x, y, width, height, format, type, data); +#if PLATFORM(CG) + // FIXME: remove this section when GL driver bug on Mac is fixed, i.e., + // when alpha is off, readPixels should set alpha to 255 instead of 0. + if ((format == GraphicsContext3D::ALPHA || format == GraphicsContext3D::RGBA) && !m_context->getContextAttributes().alpha) { + if (type == GraphicsContext3D::UNSIGNED_BYTE) { + unsigned char* pixels = reinterpret_cast<unsigned char*>(data); + for (unsigned long iy = 0; iy < height; ++iy) { + for (unsigned long ix = 0; ix < width; ++ix) { + pixels[componentsPerPixel - 1] = 255; + pixels += componentsPerPixel; + } + pixels += padding; + } + } + // FIXME: check whether we need to do the same with UNSIGNED_SHORT. + } +#endif cleanupAfterGraphicsCall(false); return array; } @@ -1555,8 +1690,21 @@ void WebGLRenderingContext::releaseShaderCompiler() void WebGLRenderingContext::renderbufferStorage(unsigned long target, unsigned long internalformat, unsigned long width, unsigned long height) { - m_context->renderbufferStorage(target, internalformat, width, height); - cleanupAfterGraphicsCall(false); + switch (internalformat) { + case GraphicsContext3D::DEPTH_COMPONENT16: + case GraphicsContext3D::RGBA4: + case GraphicsContext3D::RGB5_A1: + case GraphicsContext3D::RGB565: + case GraphicsContext3D::STENCIL_INDEX8: + case GraphicsContext3D::DEPTH_STENCIL: + m_context->renderbufferStorage(target, internalformat, width, height); + if (m_renderbufferBinding) + m_renderbufferBinding->setInternalformat(internalformat); + cleanupAfterGraphicsCall(false); + break; + default: + m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); + } } void WebGLRenderingContext::sampleCoverage(double value, bool invert) @@ -1574,10 +1722,8 @@ void WebGLRenderingContext::scissor(long x, long y, unsigned long width, unsigne void WebGLRenderingContext::shaderSource(WebGLShader* shader, const String& string, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!shader || shader->context() != this) { - m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); + if (!validateWebGLObject(shader)) return; - } m_context->shaderSource(shader, string); cleanupAfterGraphicsCall(false); } @@ -1634,12 +1780,10 @@ void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, ImageDat bool flipY, bool premultiplyAlpha, ExceptionCode& ec) { // FIXME: For now we ignore any errors returned - // FIXME: Need a form of this call that can take both a pixel buffer and flipY and premultiplyAlpha flags - UNUSED_PARAM(flipY); - UNUSED_PARAM(premultiplyAlpha); ec = 0; - m_context->texImage2D(target, level, GraphicsContext3D::RGBA, pixels->width(), pixels->height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels->data()->data()->data()); - //RLP: m_context->texImage2D(target, level, pixels, flipY, premultiplyAlpha); + Vector<uint8_t> data; + m_context->extractImageData(pixels, flipY, premultiplyAlpha, data); + m_context->texImage2D(target, level, GraphicsContext3D::RGBA, pixels->width(), pixels->height(), 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, data.data()); cleanupAfterGraphicsCall(false); } @@ -1724,11 +1868,10 @@ void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsig ImageData* pixels, bool flipY, bool premultiplyAlpha, ExceptionCode& ec) { // FIXME: For now we ignore any errors returned - UNUSED_PARAM(flipY); - UNUSED_PARAM(premultiplyAlpha); ec = 0; - m_context->texSubImage2D(target, level, xoffset, yoffset, pixels->width(), pixels->height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels->data()->data()->data()); - //RLP: m_context->texSubImage2D(target, level, xoffset, yoffset, pixels, flipY, premultiplyAlpha); + Vector<uint8_t> data; + m_context->extractImageData(pixels, flipY, premultiplyAlpha, data); + m_context->texSubImage2D(target, level, xoffset, yoffset, pixels->width(), pixels->height(), GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, data.data()); cleanupAfterGraphicsCall(false); } @@ -1790,7 +1933,12 @@ void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsig void WebGLRenderingContext::uniform1f(const WebGLUniformLocation* location, float x, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -1802,7 +1950,12 @@ void WebGLRenderingContext::uniform1f(const WebGLUniformLocation* location, floa void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, WebGLFloatArray* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -1818,7 +1971,12 @@ void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, Web void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, float* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -1834,7 +1992,12 @@ void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, flo void WebGLRenderingContext::uniform1i(const WebGLUniformLocation* location, int x, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -1846,7 +2009,12 @@ void WebGLRenderingContext::uniform1i(const WebGLUniformLocation* location, int void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, WebGLIntArray* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -1862,7 +2030,12 @@ void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, Web void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, int* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -1878,7 +2051,12 @@ void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, int void WebGLRenderingContext::uniform2f(const WebGLUniformLocation* location, float x, float y, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -1890,7 +2068,12 @@ void WebGLRenderingContext::uniform2f(const WebGLUniformLocation* location, floa void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, WebGLFloatArray* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -1907,7 +2090,12 @@ void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, Web void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, float* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -1924,7 +2112,12 @@ void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, flo void WebGLRenderingContext::uniform2i(const WebGLUniformLocation* location, int x, int y, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -1936,7 +2129,12 @@ void WebGLRenderingContext::uniform2i(const WebGLUniformLocation* location, int void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, WebGLIntArray* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -1953,7 +2151,12 @@ void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, Web void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, int* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -1970,7 +2173,12 @@ void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, int void WebGLRenderingContext::uniform3f(const WebGLUniformLocation* location, float x, float y, float z, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -1982,7 +2190,12 @@ void WebGLRenderingContext::uniform3f(const WebGLUniformLocation* location, floa void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, WebGLFloatArray* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -1999,7 +2212,12 @@ void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, Web void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, float* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2016,7 +2234,12 @@ void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, flo void WebGLRenderingContext::uniform3i(const WebGLUniformLocation* location, int x, int y, int z, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2028,7 +2251,12 @@ void WebGLRenderingContext::uniform3i(const WebGLUniformLocation* location, int void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, WebGLIntArray* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2045,7 +2273,12 @@ void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, Web void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, int* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2062,7 +2295,12 @@ void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, int void WebGLRenderingContext::uniform4f(const WebGLUniformLocation* location, float x, float y, float z, float w, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2074,7 +2312,12 @@ void WebGLRenderingContext::uniform4f(const WebGLUniformLocation* location, floa void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, WebGLFloatArray* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2091,7 +2334,12 @@ void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, Web void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, float* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2108,7 +2356,12 @@ void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, flo void WebGLRenderingContext::uniform4i(const WebGLUniformLocation* location, int x, int y, int z, int w, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2120,7 +2373,12 @@ void WebGLRenderingContext::uniform4i(const WebGLUniformLocation* location, int void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, WebGLIntArray* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2137,7 +2395,12 @@ void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, Web void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, int* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2154,7 +2417,12 @@ void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, int void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, bool transpose, WebGLFloatArray* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2171,7 +2439,12 @@ void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* locatio void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, bool transpose, float* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2188,7 +2461,12 @@ void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* locatio void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, bool transpose, WebGLFloatArray* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2205,7 +2483,12 @@ void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* locatio void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, bool transpose, float* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2222,7 +2505,12 @@ void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* locatio void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, bool transpose, WebGLFloatArray* v, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } @@ -2239,7 +2527,12 @@ void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* locatio void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, bool transpose, float* v, int size, ExceptionCode& ec) { UNUSED_PARAM(ec); - if (!location || location->program() != m_currentProgram) { + if (!location) { + m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); + return; + } + + if (location->program() != m_currentProgram) { m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); return; } diff --git a/WebCore/html/canvas/WebGLRenderingContext.h b/WebCore/html/canvas/WebGLRenderingContext.h index 90d4fab..9c58a53 100644 --- a/WebCore/html/canvas/WebGLRenderingContext.h +++ b/WebCore/html/canvas/WebGLRenderingContext.h @@ -309,6 +309,8 @@ class WebKitCSSMatrix; bool validateIndexArrayPrecise(unsigned long count, unsigned long type, long offset, long& numElementsRequired); bool validateRenderingState(long numElements); + bool validateWebGLObject(CanvasObject* object); + OwnPtr<GraphicsContext3D> m_context; bool m_needsUpdate; bool m_markedCanvasDirty; @@ -342,6 +344,11 @@ class WebKitCSSMatrix; TextureUnitState m_textureUnits[32]; unsigned long m_activeTextureUnit; + int m_packAlignment; + int m_unpackAlignment; + unsigned long m_implementationColorReadFormat; + unsigned long m_implementationColorReadType; + // Helpers for getParameter and others WebGLGetInfo getBooleanParameter(unsigned long pname); WebGLGetInfo getFloatParameter(unsigned long pname); diff --git a/WebCore/html/canvas/WebGLRenderingContext.idl b/WebCore/html/canvas/WebGLRenderingContext.idl index ce01f43..a257452 100644 --- a/WebCore/html/canvas/WebGLRenderingContext.idl +++ b/WebCore/html/canvas/WebGLRenderingContext.idl @@ -423,6 +423,7 @@ module html { const unsigned int DEPTH_COMPONENT16 = 0x81A5; const unsigned int STENCIL_INDEX = 0x1901; const unsigned int STENCIL_INDEX8 = 0x8D48; + const unsigned int DEPTH_STENCIL = 0x84F9; const unsigned int RENDERBUFFER_WIDTH = 0x8D42; const unsigned int RENDERBUFFER_HEIGHT = 0x8D43; @@ -442,6 +443,7 @@ module html { const unsigned int COLOR_ATTACHMENT0 = 0x8CE0; const unsigned int DEPTH_ATTACHMENT = 0x8D00; const unsigned int STENCIL_ATTACHMENT = 0x8D20; + const unsigned int DEPTH_STENCIL_ATTACHMENT = 0x821A; const unsigned int NONE = 0; @@ -518,7 +520,7 @@ module html { void disable(in unsigned long cap); void disableVertexAttribArray(in unsigned long index) raises(DOMException); void drawArrays(in unsigned long mode, in long first, in unsigned long count) raises(DOMException); - void drawElements (in unsigned long mode, in long count, in unsigned long type, in unsigned long offset) raises(DOMException); + void drawElements(in unsigned long mode, in long count, in unsigned long type, in unsigned long offset) raises(DOMException); void enable(in unsigned long cap); void enableVertexAttribArray(in unsigned long index) raises(DOMException); diff --git a/WebCore/html/canvas/WebGLShortArray.cpp b/WebCore/html/canvas/WebGLShortArray.cpp index f96a290..a9b0f0d 100644 --- a/WebCore/html/canvas/WebGLShortArray.cpp +++ b/WebCore/html/canvas/WebGLShortArray.cpp @@ -34,7 +34,7 @@ namespace WebCore { PassRefPtr<WebGLShortArray> WebGLShortArray::create(unsigned length) { - RefPtr<WebGLArrayBuffer> buffer = WebGLArrayBuffer::create(length * sizeof(short)); + RefPtr<WebGLArrayBuffer> buffer = WebGLArrayBuffer::create(length, sizeof(short)); return create(buffer, 0, length); } @@ -47,24 +47,17 @@ PassRefPtr<WebGLShortArray> WebGLShortArray::create(short* array, unsigned lengt } PassRefPtr<WebGLShortArray> WebGLShortArray::create(PassRefPtr<WebGLArrayBuffer> buffer, - int byteOffset, + unsigned byteOffset, unsigned length) { - // Make sure the offset results in valid alignment. - if ((byteOffset % sizeof(short)) != 0) - return NULL; - - if (buffer) { - // Check to make sure we are talking about a valid region of - // the given WebGLArrayBuffer's storage. - if ((byteOffset + (length * sizeof(short))) > buffer->byteLength()) - return NULL; - } + RefPtr<WebGLArrayBuffer> buf(buffer); + if (!verifySubRange<short>(buf, byteOffset, length)) + return 0; - return adoptRef(new WebGLShortArray(buffer, byteOffset, length)); + return adoptRef(new WebGLShortArray(buf, byteOffset, length)); } -WebGLShortArray::WebGLShortArray(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length) +WebGLShortArray::WebGLShortArray(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length) : WebGLArray(buffer, byteOffset) , m_size(length) { @@ -78,15 +71,12 @@ unsigned WebGLShortArray::byteLength() const { return m_size * sizeof(short); } -PassRefPtr<WebGLArray> WebGLShortArray::slice(unsigned offset, unsigned length) { - // Check to make sure the specified region is within the bounds of - // the WebGLArrayBuffer. - unsigned startByte = m_byteOffset + offset * sizeof(short); - unsigned limitByte = startByte + length * sizeof(short); - unsigned bufferLength = buffer()->byteLength(); - if (startByte >= bufferLength || limitByte > bufferLength) - return 0; - return create(buffer(), startByte, length); +PassRefPtr<WebGLArray> WebGLShortArray::slice(int start, int end) +{ + unsigned offset, length; + calculateOffsetAndLength(start, end, m_size, &offset, &length); + clampOffsetAndNumElements<short>(buffer(), m_byteOffset, &offset, &length); + return create(buffer(), offset, length); } void WebGLShortArray::set(WebGLShortArray* array, unsigned offset, ExceptionCode& ec) { diff --git a/WebCore/html/canvas/WebGLShortArray.h b/WebCore/html/canvas/WebGLShortArray.h index 70c66ca..af4befb 100644 --- a/WebCore/html/canvas/WebGLShortArray.h +++ b/WebCore/html/canvas/WebGLShortArray.h @@ -40,13 +40,13 @@ class WebGLShortArray : public WebGLArray { static PassRefPtr<WebGLShortArray> create(unsigned length); static PassRefPtr<WebGLShortArray> create(short* array, unsigned length); - static PassRefPtr<WebGLShortArray> create(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length); + static PassRefPtr<WebGLShortArray> create(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length); short* data() { return static_cast<short*>(baseAddress()); } virtual unsigned length() const; virtual unsigned byteLength() const; - virtual PassRefPtr<WebGLArray> slice(unsigned offset, unsigned length); + virtual PassRefPtr<WebGLArray> slice(int start, int end); void set(unsigned index, double value) { @@ -85,7 +85,7 @@ class WebGLShortArray : public WebGLArray { void set(WebGLShortArray* array, unsigned offset, ExceptionCode& ec); private: - WebGLShortArray(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length); + WebGLShortArray(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length); unsigned m_size; }; diff --git a/WebCore/html/canvas/WebGLUnsignedByteArray.cpp b/WebCore/html/canvas/WebGLUnsignedByteArray.cpp index 3fd1b50..81e0135 100644 --- a/WebCore/html/canvas/WebGLUnsignedByteArray.cpp +++ b/WebCore/html/canvas/WebGLUnsignedByteArray.cpp @@ -35,7 +35,7 @@ namespace WebCore { PassRefPtr<WebGLUnsignedByteArray> WebGLUnsignedByteArray::create(unsigned length) { - RefPtr<WebGLArrayBuffer> buffer = WebGLArrayBuffer::create(length * sizeof(unsigned char)); + RefPtr<WebGLArrayBuffer> buffer = WebGLArrayBuffer::create(length, sizeof(unsigned char)); return create(buffer, 0, length); } @@ -48,20 +48,17 @@ PassRefPtr<WebGLUnsignedByteArray> WebGLUnsignedByteArray::create(unsigned char* } PassRefPtr<WebGLUnsignedByteArray> WebGLUnsignedByteArray::create(PassRefPtr<WebGLArrayBuffer> buffer, - int byteOffset, + unsigned byteOffset, unsigned length) { - if (buffer) { - // Check to make sure we are talking about a valid region of - // the given WebGLArrayBuffer's storage. - if ((byteOffset + (length * sizeof(unsigned char))) > buffer->byteLength()) - return NULL; - } + RefPtr<WebGLArrayBuffer> buf(buffer); + if (!verifySubRange<unsigned char>(buf, byteOffset, length)) + return 0; - return adoptRef(new WebGLUnsignedByteArray(buffer, byteOffset, length)); + return adoptRef(new WebGLUnsignedByteArray(buf, byteOffset, length)); } -WebGLUnsignedByteArray::WebGLUnsignedByteArray(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length) +WebGLUnsignedByteArray::WebGLUnsignedByteArray(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length) : WebGLArray(buffer, byteOffset) , m_size(length) { @@ -75,15 +72,12 @@ unsigned WebGLUnsignedByteArray::byteLength() const { return m_size * sizeof(unsigned char); } -PassRefPtr<WebGLArray> WebGLUnsignedByteArray::slice(unsigned offset, unsigned length) { - // Check to make sure the specified region is within the bounds of - // the WebGLArrayBuffer. - unsigned startByte = m_byteOffset + offset * sizeof(unsigned char); - unsigned limitByte = startByte + length * sizeof(unsigned char); - unsigned bufferLength = buffer()->byteLength(); - if (startByte >= bufferLength || limitByte > bufferLength) - return 0; - return create(buffer(), startByte, length); +PassRefPtr<WebGLArray> WebGLUnsignedByteArray::slice(int start, int end) +{ + unsigned offset, length; + calculateOffsetAndLength(start, end, m_size, &offset, &length); + clampOffsetAndNumElements<unsigned char>(buffer(), m_byteOffset, &offset, &length); + return create(buffer(), offset, length); } void WebGLUnsignedByteArray::set(WebGLUnsignedByteArray* array, unsigned offset, ExceptionCode& ec) { diff --git a/WebCore/html/canvas/WebGLUnsignedByteArray.h b/WebCore/html/canvas/WebGLUnsignedByteArray.h index 6909de5..505b2fd 100644 --- a/WebCore/html/canvas/WebGLUnsignedByteArray.h +++ b/WebCore/html/canvas/WebGLUnsignedByteArray.h @@ -41,13 +41,13 @@ class WebGLUnsignedByteArray : public WebGLArray { static PassRefPtr<WebGLUnsignedByteArray> create(unsigned length); static PassRefPtr<WebGLUnsignedByteArray> create(unsigned char* array, unsigned length); - static PassRefPtr<WebGLUnsignedByteArray> create(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length); + static PassRefPtr<WebGLUnsignedByteArray> create(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length); unsigned char* data() { return static_cast<unsigned char*>(baseAddress()); } virtual unsigned length() const; virtual unsigned byteLength() const; - virtual PassRefPtr<WebGLArray> slice(unsigned offset, unsigned length); + virtual PassRefPtr<WebGLArray> slice(int start, int end); void set(unsigned index, double value) { @@ -86,7 +86,7 @@ class WebGLUnsignedByteArray : public WebGLArray { void set(WebGLUnsignedByteArray* array, unsigned offset, ExceptionCode& ec); private: - WebGLUnsignedByteArray(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length); + WebGLUnsignedByteArray(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length); unsigned m_size; }; diff --git a/WebCore/html/canvas/WebGLUnsignedIntArray.cpp b/WebCore/html/canvas/WebGLUnsignedIntArray.cpp index 97910f9..59d895f 100644 --- a/WebCore/html/canvas/WebGLUnsignedIntArray.cpp +++ b/WebCore/html/canvas/WebGLUnsignedIntArray.cpp @@ -35,7 +35,7 @@ namespace WebCore { PassRefPtr<WebGLUnsignedIntArray> WebGLUnsignedIntArray::create(unsigned length) { - RefPtr<WebGLArrayBuffer> buffer = WebGLArrayBuffer::create(length * sizeof(unsigned int)); + RefPtr<WebGLArrayBuffer> buffer = WebGLArrayBuffer::create(length, sizeof(unsigned int)); return create(buffer, 0, length); } @@ -48,25 +48,17 @@ PassRefPtr<WebGLUnsignedIntArray> WebGLUnsignedIntArray::create(unsigned int* ar } PassRefPtr<WebGLUnsignedIntArray> WebGLUnsignedIntArray::create(PassRefPtr<WebGLArrayBuffer> buffer, - int byteOffset, + unsigned byteOffset, unsigned length) { - // Make sure the offset results in valid alignment. - if ((byteOffset % sizeof(unsigned int)) != 0) { - return NULL; - } - - if (buffer) { - // Check to make sure we are talking about a valid region of - // the given WebGLArrayBuffer's storage. - if ((byteOffset + (length * sizeof(unsigned int))) > buffer->byteLength()) - return NULL; - } + RefPtr<WebGLArrayBuffer> buf(buffer); + if (!verifySubRange<unsigned int>(buf, byteOffset, length)) + return 0; - return adoptRef(new WebGLUnsignedIntArray(buffer, byteOffset, length)); + return adoptRef(new WebGLUnsignedIntArray(buf, byteOffset, length)); } -WebGLUnsignedIntArray::WebGLUnsignedIntArray(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length) +WebGLUnsignedIntArray::WebGLUnsignedIntArray(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length) : WebGLArray(buffer, byteOffset) , m_size(length) { @@ -80,15 +72,12 @@ unsigned WebGLUnsignedIntArray::byteLength() const { return m_size * sizeof(unsigned int); } -PassRefPtr<WebGLArray> WebGLUnsignedIntArray::slice(unsigned offset, unsigned length) { - // Check to make sure the specified region is within the bounds of - // the WebGLArrayBuffer. - unsigned startByte = m_byteOffset + offset * sizeof(unsigned int); - unsigned limitByte = startByte + length * sizeof(unsigned int); - unsigned bufferLength = buffer()->byteLength(); - if (startByte >= bufferLength || limitByte > bufferLength) - return 0; - return create(buffer(), startByte, length); +PassRefPtr<WebGLArray> WebGLUnsignedIntArray::slice(int start, int end) +{ + unsigned offset, length; + calculateOffsetAndLength(start, end, m_size, &offset, &length); + clampOffsetAndNumElements<unsigned int>(buffer(), m_byteOffset, &offset, &length); + return create(buffer(), offset, length); } void WebGLUnsignedIntArray::set(WebGLUnsignedIntArray* array, unsigned offset, ExceptionCode& ec) { diff --git a/WebCore/html/canvas/WebGLUnsignedIntArray.h b/WebCore/html/canvas/WebGLUnsignedIntArray.h index b0d9b65..6e9b220 100644 --- a/WebCore/html/canvas/WebGLUnsignedIntArray.h +++ b/WebCore/html/canvas/WebGLUnsignedIntArray.h @@ -41,13 +41,13 @@ class WebGLUnsignedIntArray : public WebGLArray { static PassRefPtr<WebGLUnsignedIntArray> create(unsigned length); static PassRefPtr<WebGLUnsignedIntArray> create(unsigned int* array, unsigned length); - static PassRefPtr<WebGLUnsignedIntArray> create(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length); + static PassRefPtr<WebGLUnsignedIntArray> create(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length); unsigned int* data() { return static_cast<unsigned int*>(baseAddress()); } virtual unsigned length() const; virtual unsigned byteLength() const; - virtual PassRefPtr<WebGLArray> slice(unsigned offset, unsigned length); + virtual PassRefPtr<WebGLArray> slice(int start, int end); void set(unsigned index, double value) { @@ -86,7 +86,7 @@ class WebGLUnsignedIntArray : public WebGLArray { void set(WebGLUnsignedIntArray* array, unsigned offset, ExceptionCode& ec); private: - WebGLUnsignedIntArray(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length); + WebGLUnsignedIntArray(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length); unsigned m_size; }; diff --git a/WebCore/html/canvas/WebGLUnsignedShortArray.cpp b/WebCore/html/canvas/WebGLUnsignedShortArray.cpp index 86fae8c..c283a81 100644 --- a/WebCore/html/canvas/WebGLUnsignedShortArray.cpp +++ b/WebCore/html/canvas/WebGLUnsignedShortArray.cpp @@ -35,7 +35,7 @@ namespace WebCore { PassRefPtr<WebGLUnsignedShortArray> WebGLUnsignedShortArray::create(unsigned length) { - RefPtr<WebGLArrayBuffer> buffer = WebGLArrayBuffer::create(length * sizeof(unsigned short)); + RefPtr<WebGLArrayBuffer> buffer = WebGLArrayBuffer::create(length, sizeof(unsigned short)); return create(buffer, 0, length); } @@ -48,26 +48,18 @@ PassRefPtr<WebGLUnsignedShortArray> WebGLUnsignedShortArray::create(unsigned sho } PassRefPtr<WebGLUnsignedShortArray> WebGLUnsignedShortArray::create(PassRefPtr<WebGLArrayBuffer> buffer, - int byteOffset, + unsigned byteOffset, unsigned length) { - // Make sure the offset results in valid alignment. - if ((byteOffset % sizeof(unsigned short)) != 0) { - return NULL; - } - - if (buffer) { - // Check to make sure we are talking about a valid region of - // the given WebGLArrayBuffer's storage. - if ((byteOffset + (length * sizeof(unsigned short))) > buffer->byteLength()) - return NULL; - } + RefPtr<WebGLArrayBuffer> buf(buffer); + if (!verifySubRange<unsigned short>(buf, byteOffset, length)) + return 0; - return adoptRef(new WebGLUnsignedShortArray(buffer, byteOffset, length)); + return adoptRef(new WebGLUnsignedShortArray(buf, byteOffset, length)); } WebGLUnsignedShortArray::WebGLUnsignedShortArray(PassRefPtr<WebGLArrayBuffer> buffer, - int byteOffset, + unsigned byteOffset, unsigned length) : WebGLArray(buffer, byteOffset) , m_size(length) @@ -82,15 +74,12 @@ unsigned WebGLUnsignedShortArray::byteLength() const { return m_size * sizeof(unsigned short); } -PassRefPtr<WebGLArray> WebGLUnsignedShortArray::slice(unsigned offset, unsigned length) { - // Check to make sure the specified region is within the bounds of - // the WebGLArrayBuffer. - unsigned startByte = m_byteOffset + offset * sizeof(unsigned short); - unsigned limitByte = startByte + length * sizeof(unsigned short); - unsigned bufferLength = buffer()->byteLength(); - if (startByte >= bufferLength || limitByte > bufferLength) - return 0; - return create(buffer(), startByte, length); +PassRefPtr<WebGLArray> WebGLUnsignedShortArray::slice(int start, int end) +{ + unsigned offset, length; + calculateOffsetAndLength(start, end, m_size, &offset, &length); + clampOffsetAndNumElements<unsigned short>(buffer(), m_byteOffset, &offset, &length); + return create(buffer(), offset, length); } void WebGLUnsignedShortArray::set(WebGLUnsignedShortArray* array, unsigned offset, ExceptionCode& ec) { diff --git a/WebCore/html/canvas/WebGLUnsignedShortArray.h b/WebCore/html/canvas/WebGLUnsignedShortArray.h index 3bad1b6..94b428a 100644 --- a/WebCore/html/canvas/WebGLUnsignedShortArray.h +++ b/WebCore/html/canvas/WebGLUnsignedShortArray.h @@ -41,13 +41,13 @@ class WebGLUnsignedShortArray : public WebGLArray { static PassRefPtr<WebGLUnsignedShortArray> create(unsigned length); static PassRefPtr<WebGLUnsignedShortArray> create(unsigned short* array, unsigned length); - static PassRefPtr<WebGLUnsignedShortArray> create(PassRefPtr<WebGLArrayBuffer> buffer, int byteOffset, unsigned length); + static PassRefPtr<WebGLUnsignedShortArray> create(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset, unsigned length); unsigned short* data() { return static_cast<unsigned short*>(baseAddress()); } virtual unsigned length() const; virtual unsigned byteLength() const; - virtual PassRefPtr<WebGLArray> slice(unsigned offset, unsigned length); + virtual PassRefPtr<WebGLArray> slice(int start, int end); void set(unsigned index, double value) { @@ -87,7 +87,7 @@ class WebGLUnsignedShortArray : public WebGLArray { void set(WebGLUnsignedShortArray* array, unsigned offset, ExceptionCode& ec); private: - WebGLUnsignedShortArray(PassRefPtr<WebGLArrayBuffer> buffer,int byteOffset,unsigned length); + WebGLUnsignedShortArray(PassRefPtr<WebGLArrayBuffer> buffer, unsigned byteOffset,unsigned length); unsigned m_size; }; |