summaryrefslogtreecommitdiffstats
path: root/WebCore/html/canvas
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/html/canvas')
-rw-r--r--WebCore/html/canvas/CanvasRenderingContext2D.cpp55
-rw-r--r--WebCore/html/canvas/CanvasRenderingContext2D.h5
-rw-r--r--WebCore/html/canvas/CheckedInt.h527
-rw-r--r--WebCore/html/canvas/WebGLBuffer.cpp66
-rw-r--r--WebCore/html/canvas/WebGLBuffer.h16
-rw-r--r--WebCore/html/canvas/WebGLGetInfo.cpp16
-rw-r--r--WebCore/html/canvas/WebGLGetInfo.h4
-rw-r--r--WebCore/html/canvas/WebGLProgram.cpp14
-rw-r--r--WebCore/html/canvas/WebGLProgram.h14
-rw-r--r--WebCore/html/canvas/WebGLRenderingContext.cpp1137
-rw-r--r--WebCore/html/canvas/WebGLRenderingContext.h101
-rw-r--r--WebCore/html/canvas/WebGLRenderingContext.idl4
-rw-r--r--WebCore/html/canvas/WebGLShader.cpp1
-rw-r--r--WebCore/html/canvas/WebGLShader.h4
14 files changed, 1440 insertions, 524 deletions
diff --git a/WebCore/html/canvas/CanvasRenderingContext2D.cpp b/WebCore/html/canvas/CanvasRenderingContext2D.cpp
index 522e51d..2ac2ca3 100644
--- a/WebCore/html/canvas/CanvasRenderingContext2D.cpp
+++ b/WebCore/html/canvas/CanvasRenderingContext2D.cpp
@@ -4,6 +4,7 @@
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
* Copyright (C) 2008 Eric Seidel <eric@webkit.org>
* Copyright (C) 2008 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -44,6 +45,7 @@
#include "GraphicsContext.h"
#include "HTMLCanvasElement.h"
#include "HTMLImageElement.h"
+#include "HTMLMediaElement.h"
#include "HTMLNames.h"
#include "ImageBuffer.h"
#include "ImageData.h"
@@ -572,9 +574,8 @@ void CanvasRenderingContext2D::quadraticCurveTo(float cpx, float cpy, float x, f
if (!state().m_invertibleCTM)
return;
if (!m_path.hasCurrentPoint())
- m_path.moveTo(FloatPoint(x, y));
- else
- m_path.addQuadCurveTo(FloatPoint(cpx, cpy), FloatPoint(x, y));
+ m_path.moveTo(FloatPoint(cpx, cpy));
+ m_path.addQuadCurveTo(FloatPoint(cpx, cpy), FloatPoint(x, y));
}
void CanvasRenderingContext2D::bezierCurveTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y)
@@ -584,9 +585,8 @@ void CanvasRenderingContext2D::bezierCurveTo(float cp1x, float cp1y, float cp2x,
if (!state().m_invertibleCTM)
return;
if (!m_path.hasCurrentPoint())
- m_path.moveTo(FloatPoint(x, y));
- else
- m_path.addBezierCurveTo(FloatPoint(cp1x, cp1y), FloatPoint(cp2x, cp2y), FloatPoint(x, y));
+ m_path.moveTo(FloatPoint(cp1x, cp1y));
+ m_path.addBezierCurveTo(FloatPoint(cp1x, cp1y), FloatPoint(cp2x, cp2y), FloatPoint(x, y));
}
void CanvasRenderingContext2D::arcTo(float x0, float y0, float x1, float y1, float r, ExceptionCode& ec)
@@ -755,8 +755,9 @@ void CanvasRenderingContext2D::fillRect(float x, float y, float width, float hei
// from the HTML5 Canvas spec:
// If x0 = x1 and y0 = y1, then the linear gradient must paint nothing
+ // If x0 = x1 and y0 = y1 and r0 = r1, then the radial gradient must paint nothing
Gradient* gradient = c->fillGradient();
- if (gradient && gradient->isZeroSize() && !gradient->isRadial())
+ if (gradient && gradient->isZeroSize())
return;
FloatRect rect(x, y, width, height);
@@ -958,12 +959,20 @@ static inline FloatRect normalizeRect(const FloatRect& rect)
void CanvasRenderingContext2D::checkOrigin(const KURL& url)
{
+ if (m_cleanOrigins.contains(url.string()))
+ return;
+
if (canvas()->securityOrigin().taintsCanvas(url))
canvas()->setOriginTainted();
+ else
+ m_cleanOrigins.add(url.string());
}
void CanvasRenderingContext2D::checkOrigin(const String& url)
{
+ if (m_cleanOrigins.contains(url))
+ return;
+
checkOrigin(KURL(KURL(), url));
}
@@ -1009,6 +1018,13 @@ void CanvasRenderingContext2D::drawImage(HTMLImageElement* image, const FloatRec
ec = 0;
+ if (!isfinite(dstRect.x()) || !isfinite(dstRect.y()) || !isfinite(dstRect.width()) || !isfinite(dstRect.height())
+ || !isfinite(srcRect.x()) || !isfinite(srcRect.y()) || !isfinite(srcRect.width()) || !isfinite(srcRect.height()))
+ return;
+
+ if (!image->complete())
+ return;
+
FloatRect imageRect = FloatRect(FloatPoint(), size(image));
if (!imageRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) {
ec = INDEX_SIZE_ERR;
@@ -1074,14 +1090,20 @@ void CanvasRenderingContext2D::drawImage(HTMLCanvasElement* sourceCanvas, const
return;
}
- ec = 0;
-
FloatRect srcCanvasRect = FloatRect(FloatPoint(), sourceCanvas->size());
+
+ if (!srcCanvasRect.width() || !srcCanvasRect.height()) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
if (!srcCanvasRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) {
ec = INDEX_SIZE_ERR;
return;
}
+ ec = 0;
+
if (!dstRect.width() || !dstRect.height())
return;
@@ -1145,6 +1167,10 @@ void CanvasRenderingContext2D::drawImage(HTMLVideoElement* video, const FloatRec
}
ec = 0;
+
+ if (video->readyState() == HTMLMediaElement::HAVE_NOTHING || video->readyState() == HTMLMediaElement::HAVE_METADATA)
+ return;
+
FloatRect videoRect = FloatRect(FloatPoint(), size(video));
if (!videoRect.contains(normalizeRect(srcRect)) || srcRect.width() == 0 || srcRect.height() == 0) {
ec = INDEX_SIZE_ERR;
@@ -1489,7 +1515,16 @@ void CanvasRenderingContext2D::setFont(const String& newFont)
state().m_font.update(styleSelector->fontSelector());
state().m_realizedFont = true;
}
-
+
+void CanvasRenderingContext2D::updateFont()
+{
+ if (!state().m_realizedFont)
+ return;
+
+ const Font& font = state().m_font;
+ font.update(font.fontSelector());
+}
+
String CanvasRenderingContext2D::textAlign() const
{
return textAlignName(state().m_textAlign);
diff --git a/WebCore/html/canvas/CanvasRenderingContext2D.h b/WebCore/html/canvas/CanvasRenderingContext2D.h
index d6b0c8a..43f3b35 100644
--- a/WebCore/html/canvas/CanvasRenderingContext2D.h
+++ b/WebCore/html/canvas/CanvasRenderingContext2D.h
@@ -34,6 +34,7 @@
#include "GraphicsTypes.h"
#include "Path.h"
#include "PlatformString.h"
+#include <wtf/text/StringHash.h>
#include <wtf/Vector.h>
#if PLATFORM(CG)
@@ -192,6 +193,7 @@ namespace WebCore {
String font() const;
void setFont(const String&);
+ void updateFont();
String textAlign() const;
void setTextAlign(const String&);
@@ -264,6 +266,9 @@ namespace WebCore {
#endif
void prepareGradientForDashboard(CanvasGradient* gradient) const;
+
+ HashSet<String> m_cleanOrigins;
+
void checkOrigin(const KURL&);
void checkOrigin(const String&);
diff --git a/WebCore/html/canvas/CheckedInt.h b/WebCore/html/canvas/CheckedInt.h
new file mode 100644
index 0000000..861e8e6
--- /dev/null
+++ b/WebCore/html/canvas/CheckedInt.h
@@ -0,0 +1,527 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Benoit Jacob <bjacob@mozilla.com>
+ * Jeff Muizelaar <jmuizelaar@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Necessary modifications are made to the original CheckedInt.h file to remove
+// dependencies on prtypes.
+// Also, change define Mozilla_CheckedInt_h to CheckedInt_h, change namespace
+// from mozilla to WebCore for easier usage.
+
+#ifndef CheckedInt_h
+#define CheckedInt_h
+
+#include <climits>
+
+namespace WebCore {
+
+namespace CheckedInt_internal {
+
+/* we don't want to use std::numeric_limits here because int... types may not support it,
+ * depending on the platform, e.g. on certain platform they use nonstandard built-in types
+ */
+
+/*** Step 1: manually record information for all the types that we want to support
+ ***/
+
+struct unsupported_type {};
+
+template<typename T> struct integer_type_manually_recorded_info
+{
+ enum { is_supported = 0 };
+ typedef unsupported_type twice_bigger_type;
+};
+
+
+#define CHECKEDINT_REGISTER_SUPPORTED_TYPE(T,_twice_bigger_type) \
+template<> struct integer_type_manually_recorded_info<T> \
+{ \
+ enum { is_supported = 1 }; \
+ typedef _twice_bigger_type twice_bigger_type; \
+ static void TYPE_NOT_SUPPORTED_BY_CheckedInt() {} \
+};
+
+CHECKEDINT_REGISTER_SUPPORTED_TYPE(int8_t, int16_t)
+CHECKEDINT_REGISTER_SUPPORTED_TYPE(uint8_t, uint16_t)
+CHECKEDINT_REGISTER_SUPPORTED_TYPE(int16_t, int32_t)
+CHECKEDINT_REGISTER_SUPPORTED_TYPE(uint16_t, uint32_t)
+CHECKEDINT_REGISTER_SUPPORTED_TYPE(int32_t, int64_t)
+CHECKEDINT_REGISTER_SUPPORTED_TYPE(uint32_t, uint64_t)
+CHECKEDINT_REGISTER_SUPPORTED_TYPE(int64_t, unsupported_type)
+CHECKEDINT_REGISTER_SUPPORTED_TYPE(uint64_t, unsupported_type)
+
+
+/*** Step 2: record some info about a given integer type,
+ *** including whether it is supported, whether a twice bigger integer type
+ *** is supported, what that twice bigger type is, and some stuff as found
+ *** in std::numeric_limits (which we don't use because int.. types may
+ *** not support it, if they are defined directly from compiler built-in types).
+ ***/
+
+template<typename T> struct is_unsupported_type { enum { answer = 0 }; };
+template<> struct is_unsupported_type<unsupported_type> { enum { answer = 1 }; };
+
+template<typename T> struct integer_traits
+{
+ typedef typename integer_type_manually_recorded_info<T>::twice_bigger_type twice_bigger_type;
+
+ enum {
+ is_supported = integer_type_manually_recorded_info<T>::is_supported,
+ twice_bigger_type_is_supported
+ = is_unsupported_type<
+ typename integer_type_manually_recorded_info<T>::twice_bigger_type
+ >::answer ? 0 : 1,
+ size = sizeof(T),
+ position_of_sign_bit = CHAR_BIT * size - 1,
+ is_signed = (T(-1) > T(0)) ? 0 : 1
+ };
+
+ static T min()
+ {
+ // bitwise ops may return a larger type, that's why we cast explicitly to T
+ return is_signed ? T(T(1) << position_of_sign_bit) : T(0);
+ }
+
+ static T max()
+ {
+ return ~min();
+ }
+};
+
+/*** Step 3: Implement the actual validity checks --- ideas taken from IntegerLib, code different.
+ ***/
+
+// bitwise ops may return a larger type, so it's good to use these inline helpers guaranteeing that
+// the result is really of type T
+
+template<typename T> inline T has_sign_bit(T x)
+{
+ return x >> integer_traits<T>::position_of_sign_bit;
+}
+
+template<typename T> inline T binary_complement(T x)
+{
+ return ~x;
+}
+
+template<typename T, typename U,
+ bool is_T_signed = integer_traits<T>::is_signed,
+ bool is_U_signed = integer_traits<U>::is_signed>
+struct is_in_range_impl {};
+
+template<typename T, typename U>
+struct is_in_range_impl<T, U, true, true>
+{
+ static T run(U x)
+ {
+ return (x <= integer_traits<T>::max()) &
+ (x >= integer_traits<T>::min());
+ }
+};
+
+template<typename T, typename U>
+struct is_in_range_impl<T, U, false, false>
+{
+ static T run(U x)
+ {
+ return x <= integer_traits<T>::max();
+ }
+};
+
+template<typename T, typename U>
+struct is_in_range_impl<T, U, true, false>
+{
+ static T run(U x)
+ {
+ if (sizeof(T) > sizeof(U))
+ return 1;
+ else
+ return x <= U(integer_traits<T>::max());
+ }
+};
+
+template<typename T, typename U>
+struct is_in_range_impl<T, U, false, true>
+{
+ static T run(U x)
+ {
+ if (sizeof(T) >= sizeof(U))
+ return x >= 0;
+ else
+ return x >= 0 && x <= U(integer_traits<T>::max());
+ }
+};
+
+template<typename T, typename U> inline T is_in_range(U x)
+{
+ return is_in_range_impl<T, U>::run(x);
+}
+
+template<typename T> inline T is_add_valid(T x, T y, T result)
+{
+ return integer_traits<T>::is_signed ?
+ // addition is valid if the sign of x+y is equal to either that of x or that of y.
+ // Beware! These bitwise operations can return a larger integer type, if T was a
+ // small type like int8, so we explicitly cast to T.
+ has_sign_bit(binary_complement(T((result^x) & (result^y))))
+ :
+ binary_complement(x) >= y;
+}
+
+template<typename T> inline T is_sub_valid(T x, T y, T result)
+{
+ return integer_traits<T>::is_signed ?
+ // substraction is valid if either x and y have same sign, or x-y and x have same sign
+ has_sign_bit(binary_complement(T((result^x) & (x^y))))
+ :
+ x >= y;
+}
+
+template<typename T,
+ bool is_signed = integer_traits<T>::is_signed,
+ bool twice_bigger_type_is_supported = integer_traits<T>::twice_bigger_type_is_supported>
+struct is_mul_valid_impl {};
+
+template<typename T>
+struct is_mul_valid_impl<T, true, true>
+{
+ static T run(T x, T y)
+ {
+ typedef typename integer_traits<T>::twice_bigger_type twice_bigger_type;
+ twice_bigger_type product = twice_bigger_type(x) * twice_bigger_type(y);
+ return is_in_range<T>(product);
+ }
+};
+
+template<typename T>
+struct is_mul_valid_impl<T, false, true>
+{
+ static T run(T x, T y)
+ {
+ typedef typename integer_traits<T>::twice_bigger_type twice_bigger_type;
+ twice_bigger_type product = twice_bigger_type(x) * twice_bigger_type(y);
+ return is_in_range<T>(product);
+ }
+};
+
+template<typename T>
+struct is_mul_valid_impl<T, true, false>
+{
+ static T run(T x, T y)
+ {
+ const T max_value = integer_traits<T>::max();
+ const T min_value = integer_traits<T>::min();
+
+ if (x == 0 || y == 0) return true;
+
+ if (x > 0) {
+ if (y > 0)
+ return x <= max_value / y;
+ else
+ return y >= min_value / x;
+ } else {
+ if (y > 0)
+ return x >= min_value / y;
+ else
+ return y >= max_value / x;
+ }
+ }
+};
+
+template<typename T>
+struct is_mul_valid_impl<T, false, false>
+{
+ static T run(T x, T y)
+ {
+ const T max_value = integer_traits<T>::max();
+ if (x == 0 || y == 0) return true;
+ return x <= max_value / y;
+ }
+};
+
+template<typename T> inline T is_mul_valid(T x, T y, T /*result not used*/)
+{
+ return is_mul_valid_impl<T>::run(x, y);
+}
+
+template<typename T> inline T is_div_valid(T x, T y)
+{
+ return integer_traits<T>::is_signed ?
+ // keep in mind that min/-1 is invalid because abs(min)>max
+ y != 0 && (x != integer_traits<T>::min() || y != T(-1))
+ :
+ y != 0;
+}
+
+} // end namespace CheckedInt_internal
+
+
+/*** Step 4: Now define the CheckedInt class.
+ ***/
+
+/** \class CheckedInt
+ * \brief Integer wrapper class checking for integer overflow and other errors
+ * \param T the integer type to wrap. Can be any of int8_t, uint8_t, int16_t, uint16_t,
+ * int32_t, uint32_t, int64_t, uint64_t.
+ *
+ * This class implements guarded integer arithmetic. Do a computation, then check that
+ * valid() returns true, you then have a guarantee that no problem, such as integer overflow,
+ * happened during this computation.
+ *
+ * The arithmetic operators in this class are guaranteed not to crash your app
+ * in case of a division by zero.
+ *
+ * For example, suppose that you want to implement a function that computes (x+y)/z,
+ * that doesn't crash if z==0, and that reports on error (divide by zero or integer overflow).
+ * You could code it as follows:
+ \code
+ bool compute_x_plus_y_over_z(int32_t x, int32_t y, int32_t z, int32_t *result)
+ {
+ CheckedInt<int32_t> checked_result = (CheckedInt<int32_t>(x) + y) / z;
+ *result = checked_result.value();
+ return checked_result.valid();
+ }
+ \endcode
+ *
+ * Implicit conversion from plain integers to checked integers is allowed. The plain integer
+ * is checked to be in range before being casted to the destination type. This means that the following
+ * lines all compile, and the resulting CheckedInts are correctly detected as valid or invalid:
+ * \code
+ CheckedInt<uint8_t> x(1); // 1 is of type int, is found to be in range for uint8_t, x is valid
+ CheckedInt<uint8_t> x(-1); // -1 is of type int, is found not to be in range for uint8_t, x is invalid
+ CheckedInt<int8_t> x(-1); // -1 is of type int, is found to be in range for int8_t, x is valid
+ CheckedInt<int8_t> x(int16_t(1000)); // 1000 is of type int16_t, is found not to be in range for int8_t, x is invalid
+ CheckedInt<int32_t> x(uint32_t(123456789)); // 3123456789 is of type uint32_t, is found not to be in range
+ // for int32_t, x is invalid
+ * \endcode
+ * Implicit conversion from
+ * checked integers to plain integers is not allowed. As shown in the
+ * above example, to get the value of a checked integer as a normal integer, call value().
+ *
+ * Arithmetic operations between checked and plain integers is allowed; the result type
+ * is the type of the checked integer.
+ *
+ * Safe integers of different types cannot be used in the same arithmetic expression.
+ */
+template<typename T>
+class CheckedInt
+{
+protected:
+ T mValue;
+ T mIsValid; // stored as a T to limit the number of integer conversions when
+ // evaluating nested arithmetic expressions.
+
+ template<typename U>
+ CheckedInt(const U& value, bool isValid) : mValue(value), mIsValid(isValid)
+ {
+ CheckedInt_internal::integer_type_manually_recorded_info<T>
+ ::TYPE_NOT_SUPPORTED_BY_CheckedInt();
+ }
+
+public:
+ /** Constructs a checked integer with given \a value. The checked integer is initialized as valid or invalid
+ * depending on whether the \a value is in range.
+ *
+ * This constructor is not explicit. Instead, the type of its argument is a separate template parameter,
+ * ensuring that no conversion is performed before this constructor is actually called.
+ * As explained in the above documentation for class CheckedInt, this constructor checks that its argument is
+ * valid.
+ */
+ template<typename U>
+ CheckedInt(const U& value)
+ : mValue(value),
+ mIsValid(CheckedInt_internal::is_in_range<T>(value))
+ {
+ CheckedInt_internal::integer_type_manually_recorded_info<T>
+ ::TYPE_NOT_SUPPORTED_BY_CheckedInt();
+ }
+
+ /** Constructs a valid checked integer with uninitialized value */
+ CheckedInt() : mIsValid(1)
+ {
+ CheckedInt_internal::integer_type_manually_recorded_info<T>
+ ::TYPE_NOT_SUPPORTED_BY_CheckedInt();
+ }
+
+ /** \returns the actual value */
+ T value() const { return mValue; }
+
+ /** \returns true if the checked integer is valid, i.e. is not the result
+ * of an invalid operation or of an operation involving an invalid checked integer
+ */
+ bool valid() const { return mIsValid; }
+
+ /** \returns the sum. Checks for overflow. */
+ template<typename U> friend CheckedInt<U> operator +(const CheckedInt<U>& lhs, const CheckedInt<U>& rhs);
+ /** Adds. Checks for overflow. \returns self reference */
+ template<typename U> CheckedInt& operator +=(const U &rhs);
+ /** \returns the difference. Checks for overflow. */
+ template<typename U> friend CheckedInt<U> operator -(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
+ /** Substracts. Checks for overflow. \returns self reference */
+ template<typename U> CheckedInt& operator -=(const U &rhs);
+ /** \returns the product. Checks for overflow. */
+ template<typename U> friend CheckedInt<U> operator *(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
+ /** Multiplies. Checks for overflow. \returns self reference */
+ template<typename U> CheckedInt& operator *=(const U &rhs);
+ /** \returns the quotient. Checks for overflow and for divide-by-zero. */
+ template<typename U> friend CheckedInt<U> operator /(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
+ /** Divides. Checks for overflow and for divide-by-zero. \returns self reference */
+ template<typename U> CheckedInt& operator /=(const U &rhs);
+
+ /** \returns the opposite value. Checks for overflow. */
+ CheckedInt operator -() const
+ {
+ T result = -value();
+ /* give the compiler a good chance to perform RVO */
+ return CheckedInt(result,
+ mIsValid & CheckedInt_internal::is_sub_valid(T(0), value(), result));
+ }
+
+ /** \returns true if the left and right hand sides are valid and have the same value. */
+ bool operator ==(const CheckedInt& other) const
+ {
+ return bool(mIsValid & other.mIsValid & T(value() == other.value()));
+ }
+
+private:
+ /** operator!= is disabled. Indeed: (a!=b) should be the same as !(a==b) but that
+ * would mean that if a or b is invalid, (a!=b) is always true, which is very tricky.
+ */
+ template<typename U>
+ bool operator !=(const U& other) const { return !(*this == other); }
+};
+
+#define CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
+template<typename T> \
+inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs) \
+{ \
+ T x = lhs.value(); \
+ T y = rhs.value(); \
+ T result = x OP y; \
+ T is_op_valid \
+ = CheckedInt_internal::is_##NAME##_valid(x, y, result); \
+ /* give the compiler a good chance to perform RVO */ \
+ return CheckedInt<T>(result, \
+ lhs.mIsValid & \
+ rhs.mIsValid & \
+ is_op_valid); \
+}
+
+CHECKEDINT_BASIC_BINARY_OPERATOR(add, +)
+CHECKEDINT_BASIC_BINARY_OPERATOR(sub, -)
+CHECKEDINT_BASIC_BINARY_OPERATOR(mul, *)
+
+// division can't be implemented by CHECKEDINT_BASIC_BINARY_OPERATOR
+// because if rhs == 0, we are not allowed to even try to compute the quotient.
+template<typename T>
+inline CheckedInt<T> operator /(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs)
+{
+ T x = lhs.value();
+ T y = rhs.value();
+ T is_op_valid = CheckedInt_internal::is_div_valid(x, y);
+ T result = is_op_valid ? (x / y) : 0;
+ /* give the compiler a good chance to perform RVO */
+ return CheckedInt<T>(result,
+ lhs.mIsValid &
+ rhs.mIsValid &
+ is_op_valid);
+}
+
+// implement cast_to_CheckedInt<T>(x), making sure that
+// - it allows x to be either a CheckedInt<T> or any integer type that can be casted to T
+// - if x is already a CheckedInt<T>, we just return a reference to it, instead of copying it (optimization)
+
+template<typename T, typename U>
+struct cast_to_CheckedInt_impl
+{
+ typedef CheckedInt<T> return_type;
+ static CheckedInt<T> run(const U& u) { return u; }
+};
+
+template<typename T>
+struct cast_to_CheckedInt_impl<T, CheckedInt<T> >
+{
+ typedef const CheckedInt<T>& return_type;
+ static const CheckedInt<T>& run(const CheckedInt<T>& u) { return u; }
+};
+
+template<typename T, typename U>
+inline typename cast_to_CheckedInt_impl<T, U>::return_type
+cast_to_CheckedInt(const U& u)
+{
+ return cast_to_CheckedInt_impl<T, U>::run(u);
+}
+
+#define CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
+template<typename T> \
+template<typename U> \
+CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(const U &rhs) \
+{ \
+ *this = *this OP cast_to_CheckedInt<T>(rhs); \
+ return *this; \
+} \
+template<typename T, typename U> \
+inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, const U &rhs) \
+{ \
+ return lhs OP cast_to_CheckedInt<T>(rhs); \
+} \
+template<typename T, typename U> \
+inline CheckedInt<T> operator OP(const U & lhs, const CheckedInt<T> &rhs) \
+{ \
+ return cast_to_CheckedInt<T>(lhs) OP rhs; \
+}
+
+CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
+CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
+CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
+CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
+
+template<typename T, typename U>
+inline bool operator ==(const CheckedInt<T> &lhs, const U &rhs)
+{
+ return lhs == cast_to_CheckedInt<T>(rhs);
+}
+
+template<typename T, typename U>
+inline bool operator ==(const U & lhs, const CheckedInt<T> &rhs)
+{
+ return cast_to_CheckedInt<T>(lhs) == rhs;
+}
+
+} // end namespace WebCore
+
+#endif /* CheckedInt_h */
diff --git a/WebCore/html/canvas/WebGLBuffer.cpp b/WebCore/html/canvas/WebGLBuffer.cpp
index 8790b1a..4c87958 100644
--- a/WebCore/html/canvas/WebGLBuffer.cpp
+++ b/WebCore/html/canvas/WebGLBuffer.cpp
@@ -39,8 +39,8 @@ PassRefPtr<WebGLBuffer> WebGLBuffer::create(WebGLRenderingContext* ctx)
WebGLBuffer::WebGLBuffer(WebGLRenderingContext* ctx)
: CanvasObject(ctx)
- , m_elementArrayBufferByteLength(0)
- , m_arrayBufferByteLength(0)
+ , m_target(0)
+ , m_byteLength(0)
, m_nextAvailableCacheEntry(0)
{
setObject(context()->graphicsContext3D()->createBuffer());
@@ -52,50 +52,51 @@ void WebGLBuffer::_deleteObject(Platform3DObject object)
context()->graphicsContext3D()->deleteBuffer(object);
}
-bool WebGLBuffer::associateBufferData(unsigned long target, int size)
+bool WebGLBuffer::associateBufferData(int size)
{
- if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
- m_elementArrayBufferByteLength = size;
- return true;
- }
-
- if (target == GraphicsContext3D::ARRAY_BUFFER) {
- m_arrayBufferByteLength = size;
+ switch (m_target) {
+ case GraphicsContext3D::ELEMENT_ARRAY_BUFFER:
+ case GraphicsContext3D::ARRAY_BUFFER:
+ m_byteLength = size;
return true;
+ default:
+ return false;
}
-
- return false;
}
-bool WebGLBuffer::associateBufferData(unsigned long target, ArrayBufferView* array)
+bool WebGLBuffer::associateBufferData(ArrayBufferView* array)
{
+ if (!m_target)
+ return false;
if (!array)
return false;
-
- if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
+
+ if (m_target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
clearCachedMaxIndices();
- m_elementArrayBufferByteLength = array->byteLength();
+ m_byteLength = array->byteLength();
// We must always clone the incoming data because client-side
// modifications without calling bufferData or bufferSubData
// must never be able to change the validation results.
m_elementArrayBuffer = ArrayBuffer::create(array->buffer().get());
return true;
}
-
- if (target == GraphicsContext3D::ARRAY_BUFFER) {
- m_arrayBufferByteLength = array->byteLength();
+
+ if (m_target == GraphicsContext3D::ARRAY_BUFFER) {
+ m_byteLength = array->byteLength();
return true;
}
return false;
}
-bool WebGLBuffer::associateBufferSubData(unsigned long target, long offset, ArrayBufferView* array)
+bool WebGLBuffer::associateBufferSubData(long offset, ArrayBufferView* array)
{
+ if (!m_target)
+ return false;
if (!array)
return false;
-
- if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
+
+ if (m_target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
clearCachedMaxIndices();
// We need to protect against integer overflow with these tests
@@ -103,22 +104,22 @@ bool WebGLBuffer::associateBufferSubData(unsigned long target, long offset, Arra
return false;
unsigned long uoffset = static_cast<unsigned long>(offset);
- if (uoffset > m_elementArrayBufferByteLength || array->byteLength() > m_elementArrayBufferByteLength - uoffset)
+ if (uoffset > m_byteLength || array->byteLength() > m_byteLength - uoffset)
return false;
memcpy(static_cast<unsigned char*>(m_elementArrayBuffer->data()) + offset, array->baseAddress(), array->byteLength());
return true;
}
-
- if (target == GraphicsContext3D::ARRAY_BUFFER)
- return array->byteLength() + offset <= m_arrayBufferByteLength;
+
+ if (m_target == GraphicsContext3D::ARRAY_BUFFER)
+ return array->byteLength() + offset <= m_byteLength;
return false;
}
-unsigned WebGLBuffer::byteLength(unsigned long target) const
+unsigned WebGLBuffer::byteLength() const
{
- return (target == GraphicsContext3D::ARRAY_BUFFER) ? m_arrayBufferByteLength : m_elementArrayBufferByteLength;
+ return m_byteLength;
}
long WebGLBuffer::getCachedMaxIndex(unsigned long type)
@@ -143,6 +144,15 @@ void WebGLBuffer::setCachedMaxIndex(unsigned long type, long value)
m_nextAvailableCacheEntry = (m_nextAvailableCacheEntry + 1) % numEntries;
}
+void WebGLBuffer::setTarget(unsigned long target)
+{
+ // In WebGL, a buffer is bound to one target in its lifetime
+ if (m_target)
+ return;
+ if (target == GraphicsContext3D::ARRAY_BUFFER || target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
+ m_target = target;
+}
+
void WebGLBuffer::clearCachedMaxIndices()
{
memset(m_maxIndexCache, 0, sizeof(m_maxIndexCache));
diff --git a/WebCore/html/canvas/WebGLBuffer.h b/WebCore/html/canvas/WebGLBuffer.h
index bd9f190..e1fec47 100644
--- a/WebCore/html/canvas/WebGLBuffer.h
+++ b/WebCore/html/canvas/WebGLBuffer.h
@@ -40,11 +40,11 @@ namespace WebCore {
static PassRefPtr<WebGLBuffer> create(WebGLRenderingContext*);
- bool associateBufferData(unsigned long target, int size);
- bool associateBufferData(unsigned long target, ArrayBufferView* array);
- bool associateBufferSubData(unsigned long target, long offset, ArrayBufferView* array);
+ bool associateBufferData(int size);
+ bool associateBufferData(ArrayBufferView* array);
+ bool associateBufferSubData(long offset, ArrayBufferView* array);
- unsigned byteLength(unsigned long target) const;
+ unsigned byteLength() const;
const ArrayBuffer* elementArrayBuffer() const { return m_elementArrayBuffer.get(); }
// Gets the cached max index for the given type. Returns -1 if
@@ -53,6 +53,9 @@ namespace WebCore {
// Sets the cached max index for the given type.
void setCachedMaxIndex(unsigned long type, long value);
+ unsigned long getTarget() const { return m_target; }
+ void setTarget(unsigned long);
+
protected:
WebGLBuffer(WebGLRenderingContext*);
@@ -61,9 +64,10 @@ namespace WebCore {
private:
virtual bool isBuffer() const { return true; }
+ unsigned long m_target;
+
RefPtr<ArrayBuffer> m_elementArrayBuffer;
- unsigned m_elementArrayBufferByteLength;
- unsigned m_arrayBufferByteLength;
+ unsigned m_byteLength;
// Optimization for index validation. For each type of index
// (i.e., UNSIGNED_SHORT), cache the maximum index in the
diff --git a/WebCore/html/canvas/WebGLGetInfo.cpp b/WebCore/html/canvas/WebGLGetInfo.cpp
index 79fc971..0c8b548 100644
--- a/WebCore/html/canvas/WebGLGetInfo.cpp
+++ b/WebCore/html/canvas/WebGLGetInfo.cpp
@@ -46,6 +46,16 @@ WebGLGetInfo::WebGLGetInfo(bool value)
{
}
+WebGLGetInfo::WebGLGetInfo(const bool* value, int size)
+ : m_type(kTypeBoolArray)
+{
+ if (!value || size <=0)
+ return;
+ m_boolArray.resize(size);
+ for (int ii = 0; ii < size; ++ii)
+ m_boolArray[ii] = value[ii];
+}
+
WebGLGetInfo::WebGLGetInfo(float value)
: m_type(kTypeFloat)
, m_float(value)
@@ -138,6 +148,12 @@ bool WebGLGetInfo::getBool() const
return m_bool;
}
+const Vector<bool>& WebGLGetInfo::getBoolArray() const
+{
+ ASSERT(getType() == kTypeBoolArray);
+ return m_boolArray;
+}
+
float WebGLGetInfo::getFloat() const
{
ASSERT(getType() == kTypeFloat);
diff --git a/WebCore/html/canvas/WebGLGetInfo.h b/WebCore/html/canvas/WebGLGetInfo.h
index b35add8..94f6f9b 100644
--- a/WebCore/html/canvas/WebGLGetInfo.h
+++ b/WebCore/html/canvas/WebGLGetInfo.h
@@ -53,6 +53,7 @@ class WebGLGetInfo {
public:
enum Type {
kTypeBool,
+ kTypeBoolArray,
kTypeFloat,
kTypeLong,
kTypeNull,
@@ -70,6 +71,7 @@ public:
};
WebGLGetInfo(bool value);
+ WebGLGetInfo(const bool* value, int size);
WebGLGetInfo(float value);
WebGLGetInfo(long value);
// Represents the NULL value and type
@@ -92,6 +94,7 @@ public:
Type getType() const;
bool getBool() const;
+ const Vector<bool>& getBoolArray() const;
float getFloat() const;
long getLong() const;
const String& getString() const;
@@ -110,6 +113,7 @@ public:
private:
Type m_type;
bool m_bool;
+ Vector<bool> m_boolArray;
float m_float;
long m_long;
String m_string;
diff --git a/WebCore/html/canvas/WebGLProgram.cpp b/WebCore/html/canvas/WebGLProgram.cpp
index 750df45..0004465 100644
--- a/WebCore/html/canvas/WebGLProgram.cpp
+++ b/WebCore/html/canvas/WebGLProgram.cpp
@@ -39,6 +39,7 @@ PassRefPtr<WebGLProgram> WebGLProgram::create(WebGLRenderingContext* ctx)
WebGLProgram::WebGLProgram(WebGLRenderingContext* ctx)
: CanvasObject(ctx)
+ , m_linkFailure(false)
{
setObject(context()->graphicsContext3D()->createProgram());
}
@@ -71,18 +72,27 @@ bool WebGLProgram::cacheActiveAttribLocations()
return true;
}
-int WebGLProgram::numActiveAttribLocations()
+int WebGLProgram::numActiveAttribLocations() const
{
return static_cast<int>(m_activeAttribLocations.size());
}
-int WebGLProgram::getActiveAttribLocation(int index)
+int WebGLProgram::getActiveAttribLocation(int index) const
{
if (index < 0 || index >= numActiveAttribLocations())
return -1;
return m_activeAttribLocations[static_cast<size_t>(index)];
}
+bool WebGLProgram::isUsingVertexAttrib0() const
+{
+ for (int ii = 0; ii < numActiveAttribLocations(); ++ii) {
+ if (!getActiveAttribLocation(ii))
+ return true;
+ }
+ return false;
+}
+
}
#endif // ENABLE(3D_CANVAS)
diff --git a/WebCore/html/canvas/WebGLProgram.h b/WebCore/html/canvas/WebGLProgram.h
index b13fc22..1049334 100644
--- a/WebCore/html/canvas/WebGLProgram.h
+++ b/WebCore/html/canvas/WebGLProgram.h
@@ -43,8 +43,16 @@ namespace WebCore {
// cacheActiveAttribLocation() is only called once after linkProgram()
// succeeds.
bool cacheActiveAttribLocations();
- int numActiveAttribLocations();
- int getActiveAttribLocation(int index);
+ int numActiveAttribLocations() const;
+ int getActiveAttribLocation(int index) const;
+
+ bool isUsingVertexAttrib0() const;
+
+ // Return true means getProgramParameter(LINK_STATUS) should return
+ // false; return false means we should actually call
+ // getProgramParameter(LINK_STATUS) to find out.
+ bool isLinkFailureFlagSet() const { return m_linkFailure; }
+ void setLinkFailureFlag(bool failed) { m_linkFailure = failed; }
protected:
WebGLProgram(WebGLRenderingContext*);
@@ -55,6 +63,8 @@ namespace WebCore {
virtual bool isProgram() const { return true; }
Vector<int> m_activeAttribLocations;
+
+ bool m_linkFailure;
};
} // namespace WebCore
diff --git a/WebCore/html/canvas/WebGLRenderingContext.cpp b/WebCore/html/canvas/WebGLRenderingContext.cpp
index 2124506..c3dea58 100644
--- a/WebCore/html/canvas/WebGLRenderingContext.cpp
+++ b/WebCore/html/canvas/WebGLRenderingContext.cpp
@@ -29,6 +29,7 @@
#include "WebGLRenderingContext.h"
+#include "CheckedInt.h"
#include "CanvasPixelArray.h"
#include "Console.h"
#include "DOMWindow.h"
@@ -52,6 +53,7 @@
#include "WebGLUniformLocation.h"
#include <wtf/ByteArray.h>
+#include <wtf/OwnArrayPtr.h>
namespace WebCore {
@@ -120,8 +122,10 @@ WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, Pa
m_context->getIntegerv(GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE, &maxCubeMapTextureSize);
m_maxCubeMapTextureSize = maxCubeMapTextureSize;
- if (!isGLES2Compliant())
+ if (!isGLES2Compliant()) {
createFallbackBlackTextures1x1();
+ initVertexAttrib0();
+ }
m_context->reshape(canvas()->width(), canvas()->height());
m_context->viewport(0, 0, canvas()->width(), canvas()->height());
}
@@ -192,7 +196,7 @@ int WebGLRenderingContext::sizeInBytes(int type, ExceptionCode& ec)
void WebGLRenderingContext::activeTexture(unsigned long texture, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if ((texture - GraphicsContext3D::TEXTURE0) > sizeof(m_textureUnits) / sizeof(TextureUnitState)) {
+ if (texture - GraphicsContext3D::TEXTURE0 >= m_textureUnits.size()) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
return;
}
@@ -204,10 +208,8 @@ void WebGLRenderingContext::activeTexture(unsigned long texture, ExceptionCode&
void WebGLRenderingContext::attachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!program || program->context() != this || !shader || shader->context() != this) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ if (!validateWebGLObject(program) || !validateWebGLObject(shader))
return;
- }
m_context->attachShader(program, shader);
cleanupAfterGraphicsCall(false);
}
@@ -228,6 +230,10 @@ void WebGLRenderingContext::bindBuffer(unsigned long target, WebGLBuffer* buffer
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
+ if (buffer && buffer->getTarget() && buffer->getTarget() != target) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return;
+ }
if (target == GraphicsContext3D::ARRAY_BUFFER)
m_boundArrayBuffer = buffer;
@@ -239,6 +245,8 @@ void WebGLRenderingContext::bindBuffer(unsigned long target, WebGLBuffer* buffer
}
m_context->bindBuffer(target, buffer);
+ if (buffer)
+ buffer->setTarget(target);
cleanupAfterGraphicsCall(false);
}
@@ -307,12 +315,20 @@ void WebGLRenderingContext::blendColor(double red, double green, double blue, do
void WebGLRenderingContext::blendEquation( unsigned long mode )
{
+ if (!isGLES2Compliant()) {
+ if (!validateBlendEquation(mode))
+ return;
+ }
m_context->blendEquation(mode);
cleanupAfterGraphicsCall(false);
}
void WebGLRenderingContext::blendEquationSeparate(unsigned long modeRGB, unsigned long modeAlpha)
{
+ if (!isGLES2Compliant()) {
+ if (!validateBlendEquation(modeRGB) || !validateBlendEquation(modeAlpha))
+ return;
+ }
m_context->blendEquationSeparate(modeRGB, modeAlpha);
cleanupAfterGraphicsCall(false);
}
@@ -334,12 +350,12 @@ void WebGLRenderingContext::bufferData(unsigned long target, int size, unsigned
{
UNUSED_PARAM(ec);
if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER && m_boundElementArrayBuffer) {
- if (!m_boundElementArrayBuffer->associateBufferData(target, size)) {
+ if (!m_boundElementArrayBuffer->associateBufferData(size)) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return;
}
} else if (target == GraphicsContext3D::ARRAY_BUFFER && m_boundArrayBuffer) {
- if (!m_boundArrayBuffer->associateBufferData(target, size)) {
+ if (!m_boundArrayBuffer->associateBufferData(size)) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return;
}
@@ -356,12 +372,12 @@ void WebGLRenderingContext::bufferData(unsigned long target, ArrayBufferView* da
{
UNUSED_PARAM(ec);
if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER && m_boundElementArrayBuffer) {
- if (!m_boundElementArrayBuffer->associateBufferData(target, data)) {
+ if (!m_boundElementArrayBuffer->associateBufferData(data)) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return;
}
} else if (target == GraphicsContext3D::ARRAY_BUFFER && m_boundArrayBuffer) {
- if (!m_boundArrayBuffer->associateBufferData(target, data)) {
+ if (!m_boundArrayBuffer->associateBufferData(data)) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return;
}
@@ -378,12 +394,12 @@ void WebGLRenderingContext::bufferSubData(unsigned long target, long offset, Arr
{
UNUSED_PARAM(ec);
if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER && m_boundElementArrayBuffer) {
- if (!m_boundElementArrayBuffer->associateBufferSubData(target, offset, data)) {
+ if (!m_boundElementArrayBuffer->associateBufferSubData(offset, data)) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return;
}
} else if (target == GraphicsContext3D::ARRAY_BUFFER && m_boundArrayBuffer) {
- if (!m_boundArrayBuffer->associateBufferSubData(target, offset, data)) {
+ if (!m_boundArrayBuffer->associateBufferSubData(offset, data)) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return;
}
@@ -562,6 +578,20 @@ void WebGLRenderingContext::deleteBuffer(WebGLBuffer* buffer)
return;
buffer->deleteObject();
+
+ if (!isGLES2Compliant()) {
+ VertexAttribState& state = m_vertexAttribState[0];
+ if (buffer == state.bufferBinding) {
+ state.bufferBinding = m_vertexAttrib0Buffer;
+ state.bytesPerElement = 0;
+ state.size = 4;
+ state.type = GraphicsContext3D::FLOAT;
+ state.normalized = false;
+ state.stride = 16;
+ state.originalStride = 0;
+ state.offset = 0;
+ }
+ }
}
void WebGLRenderingContext::deleteFramebuffer(WebGLFramebuffer* framebuffer)
@@ -638,6 +668,10 @@ void WebGLRenderingContext::detachShader(WebGLProgram* program, WebGLShader* sha
void WebGLRenderingContext::disable(unsigned long cap)
{
+ if (!isGLES2Compliant()) {
+ if (!validateCapability(cap))
+ return;
+ }
m_context->disable(cap);
cleanupAfterGraphicsCall(false);
}
@@ -652,9 +686,11 @@ void WebGLRenderingContext::disableVertexAttribArray(unsigned long index, Except
if (index < m_vertexAttribState.size())
m_vertexAttribState[index].enabled = false;
-
- m_context->disableVertexAttribArray(index);
- cleanupAfterGraphicsCall(false);
+
+ if (index > 0 || isGLES2Compliant()) {
+ m_context->disableVertexAttribArray(index);
+ cleanupAfterGraphicsCall(false);
+ }
}
bool WebGLRenderingContext::validateElementArraySize(unsigned long count, unsigned long type, long offset)
@@ -675,11 +711,11 @@ bool WebGLRenderingContext::validateElementArraySize(unsigned long count, unsign
// Make uoffset an element offset.
uoffset /= 2;
- unsigned long n = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER) / 2;
+ unsigned long n = m_boundElementArrayBuffer->byteLength() / 2;
if (uoffset > n || count > n - uoffset)
return false;
} else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
- unsigned long n = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER);
+ unsigned long n = m_boundElementArrayBuffer->byteLength();
if (uoffset > n || count > n - uoffset)
return false;
}
@@ -699,17 +735,25 @@ bool WebGLRenderingContext::validateIndexArrayConservative(unsigned long type, l
// Compute the maximum index in the entire buffer for the given type of index.
switch (type) {
case GraphicsContext3D::UNSIGNED_BYTE: {
- unsigned numElements = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER);
- const unsigned char* p = static_cast<const unsigned char*>(m_boundElementArrayBuffer->elementArrayBuffer()->data());
- for (unsigned i = 0; i < numElements; i++)
- maxIndex = max(maxIndex, static_cast<long>(p[i]));
+ unsigned numElements = m_boundElementArrayBuffer->byteLength();
+ if (!numElements)
+ maxIndex = 0;
+ else {
+ const unsigned char* p = static_cast<const unsigned char*>(m_boundElementArrayBuffer->elementArrayBuffer()->data());
+ for (unsigned i = 0; i < numElements; i++)
+ maxIndex = max(maxIndex, static_cast<long>(p[i]));
+ }
break;
}
case GraphicsContext3D::UNSIGNED_SHORT: {
- unsigned numElements = m_boundElementArrayBuffer->byteLength(GraphicsContext3D::ELEMENT_ARRAY_BUFFER) / sizeof(unsigned short);
- const unsigned short* p = static_cast<const unsigned short*>(m_boundElementArrayBuffer->elementArrayBuffer()->data());
- for (unsigned i = 0; i < numElements; i++)
- maxIndex = max(maxIndex, static_cast<long>(p[i]));
+ unsigned numElements = m_boundElementArrayBuffer->byteLength() / sizeof(unsigned short);
+ if (!numElements)
+ maxIndex = 0;
+ else {
+ const unsigned short* p = static_cast<const unsigned short*>(m_boundElementArrayBuffer->elementArrayBuffer()->data());
+ for (unsigned i = 0; i < numElements; i++)
+ maxIndex = max(maxIndex, static_cast<long>(p[i]));
+ }
break;
}
default:
@@ -766,8 +810,10 @@ bool WebGLRenderingContext::validateRenderingState(long numElementsRequired)
if (!m_currentProgram)
return false;
+ int numAttribStates = static_cast<int>(m_vertexAttribState.size());
+
// Look in each enabled vertex attrib and check if they've been bound to a buffer.
- for (size_t i = 0; i < m_vertexAttribState.size(); ++i) {
+ for (int i = 0; i < numAttribStates; ++i) {
if (m_vertexAttribState[i].enabled
&& (!m_vertexAttribState[i].bufferBinding || !m_vertexAttribState[i].bufferBinding->object()))
return false;
@@ -776,13 +822,21 @@ bool WebGLRenderingContext::validateRenderingState(long numElementsRequired)
// Look in each consumed vertex attrib (by the current program) and find the smallest buffer size
long smallestNumElements = LONG_MAX;
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 (state.enabled) {
+ // Avoid off-by-one errors in numElements computation.
+ // For the last element, we will only touch the data for the
+ // element and nothing beyond it.
+ long bytesRemaining = state.bufferBinding->byteLength() - state.offset;
+ long numElements = 0;
+ if (bytesRemaining >= state.bytesPerElement)
+ numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride;
+ if (numElements < smallestNumElements)
+ smallestNumElements = numElements;
+ }
}
}
@@ -817,18 +871,26 @@ void WebGLRenderingContext::drawArrays(unsigned long mode, long first, long coun
return;
}
- if (!count)
- return;
-
// Ensure we have a valid rendering state
- if (!validateRenderingState(first + count)) {
+ CheckedInt<int32_t> checkedFirst(first);
+ CheckedInt<int32_t> checkedCount(count);
+ CheckedInt<int32_t> checkedSum = checkedFirst + checkedCount;
+ if (!checkedSum.valid() || !validateRenderingState(checkedSum.value())) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
- handleNPOTTextures(true);
+ bool vertexAttrib0Simulated = false;
+ if (!isGLES2Compliant()) {
+ vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
+ handleNPOTTextures(true);
+ }
m_context->drawArrays(mode, first, count);
- handleNPOTTextures(false);
+ if (!isGLES2Compliant()) {
+ handleNPOTTextures(false);
+ if (vertexAttrib0Simulated)
+ restoreStatesAfterVertexAttrib0Simulation();
+ }
cleanupAfterGraphicsCall(true);
}
@@ -853,9 +915,6 @@ void WebGLRenderingContext::drawElements(unsigned long mode, long count, unsigne
return;
}
- if (!count)
- return;
-
// Ensure we have a valid rendering state
long numElements;
@@ -870,14 +929,26 @@ void WebGLRenderingContext::drawElements(unsigned long mode, long count, unsigne
return;
}
- handleNPOTTextures(true);
+ bool vertexAttrib0Simulated = false;
+ if (!isGLES2Compliant()) {
+ vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
+ handleNPOTTextures(true);
+ }
m_context->drawElements(mode, count, type, offset);
- handleNPOTTextures(false);
+ if (!isGLES2Compliant()) {
+ handleNPOTTextures(false);
+ if (vertexAttrib0Simulated)
+ restoreStatesAfterVertexAttrib0Simulation();
+ }
cleanupAfterGraphicsCall(true);
}
void WebGLRenderingContext::enable(unsigned long cap)
{
+ if (!isGLES2Compliant()) {
+ if (!validateCapability(cap))
+ return;
+ }
m_context->enable(cap);
cleanupAfterGraphicsCall(false);
}
@@ -1040,6 +1111,33 @@ PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveUniform(WebGLProgram
return WebGLActiveInfo::create(info.name, info.type, info.size);
}
+bool WebGLRenderingContext::getAttachedShaders(WebGLProgram* program, Vector<WebGLShader*>& shaderObjects, ExceptionCode& ec)
+{
+ UNUSED_PARAM(ec);
+ shaderObjects.clear();
+ if (!validateWebGLObject(program))
+ return false;
+ int numShaders = 0;
+ m_context->getProgramiv(program, GraphicsContext3D::ATTACHED_SHADERS, &numShaders);
+ if (numShaders) {
+ OwnArrayPtr<unsigned int> shaders(new unsigned int[numShaders]);
+ int count;
+ m_context->getAttachedShaders(program, numShaders, &count, shaders.get());
+ if (count != numShaders)
+ return false;
+ shaderObjects.resize(numShaders);
+ for (int ii = 0; ii < numShaders; ++ii) {
+ WebGLShader* shader = findShader(shaders[ii]);
+ if (!shader) {
+ shaderObjects.clear();
+ return false;
+ }
+ shaderObjects[ii] = shader;
+ }
+ }
+ return true;
+}
+
int WebGLRenderingContext::getAttribLocation(WebGLProgram* program, const String& name)
{
return m_context->getAttribLocation(program, name);
@@ -1162,7 +1260,7 @@ WebGLGetInfo WebGLRenderingContext::getParameter(unsigned long pname, ExceptionC
case GraphicsContext3D::COLOR_CLEAR_VALUE:
return getWebGLFloatArrayParameter(pname);
case GraphicsContext3D::COLOR_WRITEMASK:
- return getWebGLUnsignedByteArrayParameter(pname);
+ return getBooleanArrayParameter(pname);
case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS:
// Defined as null in the spec
return WebGLGetInfo();
@@ -1318,10 +1416,14 @@ WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, u
int value = 0;
switch (pname) {
case GraphicsContext3D::DELETE_STATUS:
- case GraphicsContext3D::LINK_STATUS:
case GraphicsContext3D::VALIDATE_STATUS:
m_context->getProgramiv(program, pname, &value);
return WebGLGetInfo(static_cast<bool>(value));
+ case GraphicsContext3D::LINK_STATUS:
+ if (program->isLinkFailureFlagSet())
+ return WebGLGetInfo(false);
+ m_context->getProgramiv(program, pname, &value);
+ return WebGLGetInfo(static_cast<bool>(value));
case GraphicsContext3D::INFO_LOG_LENGTH:
case GraphicsContext3D::ATTACHED_SHADERS:
case GraphicsContext3D::ACTIVE_ATTRIBUTES:
@@ -1469,13 +1571,24 @@ WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebG
ActiveInfo info;
if (!m_context->getActiveUniform(program, i, info))
return WebGLGetInfo();
- // Now need to look this up by name again to find its location
- long loc = m_context->getUniformLocation(program, info.name);
- if (loc == location) {
- // Found it. Use the type in the ActiveInfo to determine the return type.
- GraphicsContext3D::WebGLEnumType baseType;
- unsigned length;
- switch (info.type) {
+ // Strip "[0]" from the name if it's an array.
+ if (info.size > 1)
+ info.name = info.name.left(info.name.length() - 3);
+ // If it's an array, we need to iterate through each element, appending "[index]" to the name.
+ for (int index = 0; index < info.size; ++index) {
+ String name = info.name;
+ if (info.size > 1 && index >= 1) {
+ name.append('[');
+ name.append(String::number(index));
+ name.append(']');
+ }
+ // Now need to look this up by name again to find its location
+ long loc = m_context->getUniformLocation(program, name);
+ if (loc == location) {
+ // Found it. Use the type in the ActiveInfo to determine the return type.
+ GraphicsContext3D::WebGLEnumType baseType;
+ unsigned length;
+ switch (info.type) {
case GraphicsContext3D::BOOL:
baseType = GraphicsContext3D::BOOL;
length = 1;
@@ -1541,38 +1654,36 @@ WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebG
// FIXME: what to do about samplers?
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return WebGLGetInfo();
- }
- switch (baseType) {
- case GraphicsContext3D::FLOAT: {
- float value[16] = {0};
- m_context->getUniformfv(program, location, value);
- if (length == 1)
- return WebGLGetInfo(value[0]);
- else
+ }
+ switch (baseType) {
+ case GraphicsContext3D::FLOAT: {
+ float value[16] = {0};
+ m_context->getUniformfv(program, location, value);
+ if (length == 1)
+ return WebGLGetInfo(value[0]);
return WebGLGetInfo(Float32Array::create(value, length));
- }
- case GraphicsContext3D::INT: {
- int value[16] = {0};
- m_context->getUniformiv(program, location, value);
- if (length == 1)
- return WebGLGetInfo(static_cast<long>(value[0]));
- else
+ }
+ case GraphicsContext3D::INT: {
+ int value[16] = {0};
+ m_context->getUniformiv(program, location, value);
+ if (length == 1)
+ return WebGLGetInfo(static_cast<long>(value[0]));
return WebGLGetInfo(Int32Array::create(value, length));
- }
- case GraphicsContext3D::BOOL: {
- int value[16] = {0};
- m_context->getUniformiv(program, location, value);
- if (length == 1)
+ }
+ case GraphicsContext3D::BOOL: {
+ int value[16] = {0};
+ m_context->getUniformiv(program, location, value);
+ if (length > 1) {
+ unsigned char boolValue[16] = {0};
+ for (unsigned j = 0; j < length; j++)
+ boolValue[j] = static_cast<bool>(value[j]);
+ return WebGLGetInfo(Uint8Array::create(boolValue, length));
+ }
return WebGLGetInfo(static_cast<bool>(value[0]));
- else {
- unsigned char boolValue[16] = {0};
- for (unsigned j = 0; j < length; j++)
- boolValue[j] = static_cast<bool>(value[j]);
- return WebGLGetInfo(Uint8Array::create(boolValue, length));
}
- }
- default:
- notImplemented();
+ default:
+ notImplemented();
+ }
}
}
}
@@ -1597,39 +1708,48 @@ WebGLGetInfo WebGLRenderingContext::getVertexAttrib(unsigned long index, unsigne
{
UNUSED_PARAM(ec);
WebGLStateRestorer(this, false);
- switch (pname) {
- case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: {
- int name = 0;
- m_context->getVertexAttribiv(index, pname, &name);
- return WebGLGetInfo(PassRefPtr<WebGLBuffer>(findBuffer(static_cast<Platform3DObject>(name))));
+ if (index >= m_maxVertexAttribs) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ return WebGLGetInfo();
}
+ switch (pname) {
+ case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
+ if (!isGLES2Compliant() && !index && m_vertexAttribState[0].bufferBinding == m_vertexAttrib0Buffer
+ || index >= m_vertexAttribState.size()
+ || !m_vertexAttribState[index].bufferBinding
+ || !m_vertexAttribState[index].bufferBinding->object())
+ return WebGLGetInfo();
+ return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_vertexAttribState[index].bufferBinding));
case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
- case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED: {
- int value = 0;
- m_context->getVertexAttribiv(index, pname, &value);
- return WebGLGetInfo(static_cast<bool>(value));
- }
+ if (index >= m_vertexAttribState.size())
+ return WebGLGetInfo(false);
+ return WebGLGetInfo(m_vertexAttribState[index].enabled);
+ case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
+ if (index >= m_vertexAttribState.size())
+ return WebGLGetInfo(false);
+ return WebGLGetInfo(m_vertexAttribState[index].normalized);
case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
- case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE: {
- int value = 0;
- m_context->getVertexAttribiv(index, pname, &value);
- return WebGLGetInfo(static_cast<long>(value));
- }
- case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE: {
- int value = 0;
- m_context->getVertexAttribiv(index, pname, &value);
- return WebGLGetInfo(static_cast<unsigned long>(value));
- }
- case GraphicsContext3D::CURRENT_VERTEX_ATTRIB: {
- float value[4] = {0};
- m_context->getVertexAttribfv(index, pname, value);
- return WebGLGetInfo(Float32Array::create(value, 4));
- }
- default: {
+ if (index >= m_vertexAttribState.size())
+ return WebGLGetInfo(static_cast<long>(4));
+ return WebGLGetInfo(m_vertexAttribState[index].size);
+ case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
+ if (index >= m_vertexAttribState.size())
+ return WebGLGetInfo(static_cast<long>(0));
+ return WebGLGetInfo(m_vertexAttribState[index].originalStride);
+ case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
+ if (index >= m_vertexAttribState.size())
+ return WebGLGetInfo(static_cast<unsigned long>(GraphicsContext3D::FLOAT));
+ return WebGLGetInfo(m_vertexAttribState[index].type);
+ case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
+ if (index >= m_vertexAttribState.size()) {
+ float value[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
+ return WebGLGetInfo(Float32Array::create(value, 4));
+ }
+ return WebGLGetInfo(Float32Array::create(m_vertexAttribState[index].value, 4));
+ default:
m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
return WebGLGetInfo();
}
- }
}
long WebGLRenderingContext::getVertexAttribOffset(unsigned long index, unsigned long pname)
@@ -1641,6 +1761,12 @@ long WebGLRenderingContext::getVertexAttribOffset(unsigned long index, unsigned
void WebGLRenderingContext::hint(unsigned long target, unsigned long mode)
{
+ if (!isGLES2Compliant()) {
+ if (target != GraphicsContext3D::GENERATE_MIPMAP_HINT) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
+ return;
+ }
+ }
m_context->hint(target, mode);
cleanupAfterGraphicsCall(false);
}
@@ -1655,6 +1781,10 @@ bool WebGLRenderingContext::isBuffer(WebGLBuffer* buffer)
bool WebGLRenderingContext::isEnabled(unsigned long cap)
{
+ if (!isGLES2Compliant()) {
+ if (!validateCapability(cap))
+ return false;
+ }
return m_context->isEnabled(cap);
}
@@ -1709,6 +1839,28 @@ void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec
UNUSED_PARAM(ec);
if (!validateWebGLObject(program))
return;
+ if (!isGLES2Compliant()) {
+ Vector<WebGLShader*> shaders;
+ bool succeed = getAttachedShaders(program, shaders, ec);
+ if (succeed) {
+ bool vShader = false;
+ bool fShader = false;
+ for (size_t ii = 0; ii < shaders.size() && (!vShader || !fShader); ++ii) {
+ if (shaders[ii]->getType() == GraphicsContext3D::VERTEX_SHADER)
+ vShader = true;
+ else if (shaders[ii]->getType() == GraphicsContext3D::FRAGMENT_SHADER)
+ fShader = true;
+ }
+ if (!vShader || !fShader)
+ succeed = false;
+ }
+ if (!succeed) {
+ program->setLinkFailureFlag(true);
+ return;
+ }
+ program->setLinkFailureFlag(false);
+ }
+
m_context->linkProgram(program);
program->cacheActiveAttribLocations();
cleanupAfterGraphicsCall(false);
@@ -1716,22 +1868,26 @@ void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec
void WebGLRenderingContext::pixelStorei(unsigned long pname, long param)
{
- if (pname == GraphicsContext3D::UNPACK_FLIP_Y_WEBGL) {
+ switch (pname) {
+ case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
m_unpackFlipY = param;
- } else if (pname == GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL) {
+ break;
+ case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
m_unpackPremultiplyAlpha = param;
- } else {
+ break;
+ case GraphicsContext3D::PACK_ALIGNMENT:
+ case GraphicsContext3D::UNPACK_ALIGNMENT:
m_context->pixelStorei(pname, param);
if (param == 1 || param == 2 || param == 4 || param == 8) {
- switch (pname) {
- case GraphicsContext3D::PACK_ALIGNMENT:
+ if (pname == GraphicsContext3D::PACK_ALIGNMENT)
m_packAlignment = static_cast<int>(param);
- break;
- case GraphicsContext3D::UNPACK_ALIGNMENT:
+ else // GraphicsContext3D::UNPACK_ALIGNMENT:
m_unpackAlignment = static_cast<int>(param);
- break;
- }
}
+ break;
+ default:
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
+ return;
}
cleanupAfterGraphicsCall(false);
}
@@ -1940,9 +2096,27 @@ void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned
unsigned width, unsigned height, unsigned border,
unsigned format, unsigned type, ArrayBufferView* pixels, ExceptionCode& ec)
{
- // FIXME: Need to make sure passed buffer has enough bytes to define the texture
+ if (!validateTexFuncData(width, height, format, type, pixels))
+ return;
+ void* data = pixels ? pixels->baseAddress() : 0;
+ Vector<uint8_t> tempData;
+ bool changeUnpackAlignment = false;
+ if (pixels && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
+ if (!m_context->extractTextureData(width, height, format, type,
+ m_unpackAlignment,
+ m_unpackFlipY, m_unpackPremultiplyAlpha,
+ pixels,
+ tempData))
+ return;
+ data = tempData.data();
+ changeUnpackAlignment = true;
+ }
+ if (changeUnpackAlignment)
+ m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
texImage2DBase(target, level, internalformat, width, height, border,
- format, type, pixels ? pixels->baseAddress() : 0, ec);
+ format, type, data, ec);
+ if (changeUnpackAlignment)
+ m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
}
void WebGLRenderingContext::texImage2D(unsigned target, unsigned level, unsigned internalformat,
@@ -2196,8 +2370,26 @@ void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsig
unsigned width, unsigned height,
unsigned format, unsigned type, ArrayBufferView* pixels, ExceptionCode& ec)
{
- // FIXME: Need to make sure passed buffer has enough bytes to define the texture
- texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, type, pixels ? pixels->baseAddress() : 0, ec);
+ if (!validateTexFuncData(width, height, format, type, pixels))
+ return;
+ void* data = pixels ? pixels->baseAddress() : 0;
+ Vector<uint8_t> tempData;
+ bool changeUnpackAlignment = false;
+ if (pixels && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
+ if (!m_context->extractTextureData(width, height, format, type,
+ m_unpackAlignment,
+ m_unpackFlipY, m_unpackPremultiplyAlpha,
+ pixels,
+ tempData))
+ return;
+ data = tempData.data();
+ changeUnpackAlignment = true;
+ }
+ if (changeUnpackAlignment)
+ m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
+ texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, type, data, ec);
+ if (changeUnpackAlignment)
+ m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
}
void WebGLRenderingContext::texSubImage2D(unsigned target, unsigned level, unsigned xoffset, unsigned yoffset,
@@ -2381,18 +2573,9 @@ void WebGLRenderingContext::uniform1f(const WebGLUniformLocation* location, floa
void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
- return;
-
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ if (!validateUniformParameters(location, v, 1))
return;
- }
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
m_context->uniform1fv(location->location(), v->data(), v->length());
cleanupAfterGraphicsCall(false);
}
@@ -2400,18 +2583,9 @@ void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, Flo
void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, float* v, int size, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
+ if (!validateUniformParameters(location, v, size, 1))
return;
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
- return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
m_context->uniform1fv(location->location(), v, size);
cleanupAfterGraphicsCall(false);
}
@@ -2434,18 +2608,9 @@ void WebGLRenderingContext::uniform1i(const WebGLUniformLocation* location, int
void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
- return;
-
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ if (!validateUniformParameters(location, v, 1))
return;
- }
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
m_context->uniform1iv(location->location(), v->data(), v->length());
cleanupAfterGraphicsCall(false);
}
@@ -2453,18 +2618,9 @@ void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, Int
void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, int* v, int size, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
+ if (!validateUniformParameters(location, v, size, 1))
return;
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
- return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
m_context->uniform1iv(location->location(), v, size);
cleanupAfterGraphicsCall(false);
}
@@ -2487,19 +2643,9 @@ void WebGLRenderingContext::uniform2f(const WebGLUniformLocation* location, floa
void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
+ if (!validateUniformParameters(location, v, 2))
return;
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
- return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- // FIXME: length needs to be a multiple of 2
m_context->uniform2fv(location->location(), v->data(), v->length() / 2);
cleanupAfterGraphicsCall(false);
}
@@ -2507,19 +2653,9 @@ void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, Flo
void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, float* v, int size, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
+ if (!validateUniformParameters(location, v, size, 2))
return;
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
- return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- // FIXME: length needs to be a multiple of 2
m_context->uniform2fv(location->location(), v, size / 2);
cleanupAfterGraphicsCall(false);
}
@@ -2542,19 +2678,9 @@ void WebGLRenderingContext::uniform2i(const WebGLUniformLocation* location, int
void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
- return;
-
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ if (!validateUniformParameters(location, v, 2))
return;
- }
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- // FIXME: length needs to be a multiple of 2
m_context->uniform2iv(location->location(), v->data(), v->length() / 2);
cleanupAfterGraphicsCall(false);
}
@@ -2562,19 +2688,9 @@ void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, Int
void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, int* v, int size, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
+ if (!validateUniformParameters(location, v, size, 2))
return;
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
- return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- // FIXME: length needs to be a multiple of 2
m_context->uniform2iv(location->location(), v, size / 2);
cleanupAfterGraphicsCall(false);
}
@@ -2597,19 +2713,9 @@ void WebGLRenderingContext::uniform3f(const WebGLUniformLocation* location, floa
void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
- return;
-
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ if (!validateUniformParameters(location, v, 3))
return;
- }
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- // FIXME: length needs to be a multiple of 3
m_context->uniform3fv(location->location(), v->data(), v->length() / 3);
cleanupAfterGraphicsCall(false);
}
@@ -2617,19 +2723,9 @@ void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, Flo
void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, float* v, int size, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
+ if (!validateUniformParameters(location, v, size, 3))
return;
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
- return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- // FIXME: length needs to be a multiple of 3
m_context->uniform3fv(location->location(), v, size / 3);
cleanupAfterGraphicsCall(false);
}
@@ -2652,19 +2748,9 @@ void WebGLRenderingContext::uniform3i(const WebGLUniformLocation* location, int
void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
+ if (!validateUniformParameters(location, v, 3))
return;
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
- return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- // FIXME: length needs to be a multiple of 3
m_context->uniform3iv(location->location(), v->data(), v->length() / 3);
cleanupAfterGraphicsCall(false);
}
@@ -2672,19 +2758,9 @@ void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, Int
void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, int* v, int size, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
+ if (!validateUniformParameters(location, v, size, 3))
return;
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
- return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- // FIXME: length needs to be a multiple of 3
m_context->uniform3iv(location->location(), v, size / 3);
cleanupAfterGraphicsCall(false);
}
@@ -2707,19 +2783,9 @@ void WebGLRenderingContext::uniform4f(const WebGLUniformLocation* location, floa
void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
- return;
-
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ if (!validateUniformParameters(location, v, 4))
return;
- }
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- // FIXME: length needs to be a multiple of 4
m_context->uniform4fv(location->location(), v->data(), v->length() / 4);
cleanupAfterGraphicsCall(false);
}
@@ -2727,19 +2793,9 @@ void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, Flo
void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, float* v, int size, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
+ if (!validateUniformParameters(location, v, size, 4))
return;
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
- return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- // FIXME: length needs to be a multiple of 4
m_context->uniform4fv(location->location(), v, size / 4);
cleanupAfterGraphicsCall(false);
}
@@ -2762,19 +2818,9 @@ void WebGLRenderingContext::uniform4i(const WebGLUniformLocation* location, int
void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
+ if (!validateUniformParameters(location, v, 4))
return;
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
- return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- // FIXME: length needs to be a multiple of 4
m_context->uniform4iv(location->location(), v->data(), v->length() / 4);
cleanupAfterGraphicsCall(false);
}
@@ -2782,19 +2828,9 @@ void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, Int
void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, int* v, int size, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
+ if (!validateUniformParameters(location, v, size, 4))
return;
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
- return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- // FIXME: length needs to be a multiple of 4
m_context->uniform4iv(location->location(), v, size / 4);
cleanupAfterGraphicsCall(false);
}
@@ -2802,19 +2838,8 @@ void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, int
void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, bool transpose, Float32Array* v, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
- return;
-
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
- return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ if (!validateUniformMatrixParameters(location, transpose, v, 4))
return;
- }
- // FIXME: length needs to be a multiple of 4
m_context->uniformMatrix2fv(location->location(), transpose, v->data(), v->length() / 4);
cleanupAfterGraphicsCall(false);
}
@@ -2822,19 +2847,8 @@ 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)
+ if (!validateUniformMatrixParameters(location, transpose, v, size, 4))
return;
-
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
- return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- // FIXME: length needs to be a multiple of 4
m_context->uniformMatrix2fv(location->location(), transpose, v, size / 4);
cleanupAfterGraphicsCall(false);
}
@@ -2842,19 +2856,8 @@ void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* locatio
void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, bool transpose, Float32Array* v, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
+ if (!validateUniformMatrixParameters(location, transpose, v, 9))
return;
-
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
- return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- // FIXME: length needs to be a multiple of 9
m_context->uniformMatrix3fv(location->location(), transpose, v->data(), v->length() / 9);
cleanupAfterGraphicsCall(false);
}
@@ -2862,19 +2865,8 @@ 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)
- return;
-
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ if (!validateUniformMatrixParameters(location, transpose, v, size, 9))
return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- // FIXME: length needs to be a multiple of 9
m_context->uniformMatrix3fv(location->location(), transpose, v, size / 9);
cleanupAfterGraphicsCall(false);
}
@@ -2882,19 +2874,8 @@ void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* locatio
void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, bool transpose, Float32Array* v, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!location)
- return;
-
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
- return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ if (!validateUniformMatrixParameters(location, transpose, v, 16))
return;
- }
- // FIXME: length needs to be a multiple of 16
m_context->uniformMatrix4fv(location->location(), transpose, v->data(), v->length() / 16);
cleanupAfterGraphicsCall(false);
}
@@ -2902,19 +2883,8 @@ 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)
+ if (!validateUniformMatrixParameters(location, transpose, v, size, 16))
return;
-
- if (location->program() != m_currentProgram) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
- return;
- }
-
- if (!v) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
- return;
- }
- // FIXME: length needs to be a multiple of 16
m_context->uniformMatrix4fv(location->location(), transpose, v, size / 16);
cleanupAfterGraphicsCall(false);
}
@@ -2922,11 +2892,10 @@ void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* locatio
void WebGLRenderingContext::useProgram(WebGLProgram* program, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!program || program->context() != this) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ if (program && program->context() != this) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
-
m_currentProgram = program;
m_context->useProgram(program);
cleanupAfterGraphicsCall(false);
@@ -2935,139 +2904,111 @@ void WebGLRenderingContext::useProgram(WebGLProgram* program, ExceptionCode& ec)
void WebGLRenderingContext::validateProgram(WebGLProgram* program, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
- if (!program || program->context() != this) {
- m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ if (!validateWebGLObject(program))
return;
- }
-
m_context->validateProgram(program);
cleanupAfterGraphicsCall(false);
}
-void WebGLRenderingContext::vertexAttrib1f(unsigned long indx, float v0)
+void WebGLRenderingContext::vertexAttrib1f(unsigned long index, float v0)
{
- m_context->vertexAttrib1f(indx, v0);
- cleanupAfterGraphicsCall(false);
+ vertexAttribfImpl(index, 1, v0, 0.0f, 0.0f, 1.0f);
}
-void WebGLRenderingContext::vertexAttrib1fv(unsigned long indx, Float32Array* v)
+void WebGLRenderingContext::vertexAttrib1fv(unsigned long index, Float32Array* v)
{
- // FIXME: Need to make sure array is big enough for attribute being set
- m_context->vertexAttrib1fv(indx, v->data());
- cleanupAfterGraphicsCall(false);
+ vertexAttribfvImpl(index, v, 1);
}
-void WebGLRenderingContext::vertexAttrib1fv(unsigned long indx, float* v, int size)
+void WebGLRenderingContext::vertexAttrib1fv(unsigned long index, float* v, int size)
{
- // FIXME: Need to make sure array is big enough for attribute being set
- UNUSED_PARAM(size);
-
- m_context->vertexAttrib1fv(indx, v);
- cleanupAfterGraphicsCall(false);
+ vertexAttribfvImpl(index, v, size, 1);
}
-void WebGLRenderingContext::vertexAttrib2f(unsigned long indx, float v0, float v1)
+void WebGLRenderingContext::vertexAttrib2f(unsigned long index, float v0, float v1)
{
- m_context->vertexAttrib2f(indx, v0, v1);
- cleanupAfterGraphicsCall(false);
+ vertexAttribfImpl(index, 2, v0, v1, 0.0f, 1.0f);
}
-void WebGLRenderingContext::vertexAttrib2fv(unsigned long indx, Float32Array* v)
+void WebGLRenderingContext::vertexAttrib2fv(unsigned long index, Float32Array* v)
{
- // FIXME: Need to make sure array is big enough for attribute being set
- m_context->vertexAttrib2fv(indx, v->data());
- cleanupAfterGraphicsCall(false);
+ vertexAttribfvImpl(index, v, 2);
}
-void WebGLRenderingContext::vertexAttrib2fv(unsigned long indx, float* v, int size)
+void WebGLRenderingContext::vertexAttrib2fv(unsigned long index, float* v, int size)
{
- // FIXME: Need to make sure array is big enough for attribute being set
- UNUSED_PARAM(size);
-
- m_context->vertexAttrib2fv(indx, v);
- cleanupAfterGraphicsCall(false);
+ vertexAttribfvImpl(index, v, size, 2);
}
-void WebGLRenderingContext::vertexAttrib3f(unsigned long indx, float v0, float v1, float v2)
+void WebGLRenderingContext::vertexAttrib3f(unsigned long index, float v0, float v1, float v2)
{
- m_context->vertexAttrib3f(indx, v0, v1, v2);
- cleanupAfterGraphicsCall(false);
+ vertexAttribfImpl(index, 3, v0, v1, v2, 1.0f);
}
-void WebGLRenderingContext::vertexAttrib3fv(unsigned long indx, Float32Array* v)
+void WebGLRenderingContext::vertexAttrib3fv(unsigned long index, Float32Array* v)
{
- // FIXME: Need to make sure array is big enough for attribute being set
- m_context->vertexAttrib3fv(indx, v->data());
- cleanupAfterGraphicsCall(false);
+ vertexAttribfvImpl(index, v, 3);
}
-void WebGLRenderingContext::vertexAttrib3fv(unsigned long indx, float* v, int size)
+void WebGLRenderingContext::vertexAttrib3fv(unsigned long index, float* v, int size)
{
- // FIXME: Need to make sure array is big enough for attribute being set
- UNUSED_PARAM(size);
-
- m_context->vertexAttrib3fv(indx, v);
- cleanupAfterGraphicsCall(false);
+ vertexAttribfvImpl(index, v, size, 3);
}
-void WebGLRenderingContext::vertexAttrib4f(unsigned long indx, float v0, float v1, float v2, float v3)
+void WebGLRenderingContext::vertexAttrib4f(unsigned long index, float v0, float v1, float v2, float v3)
{
- m_context->vertexAttrib4f(indx, v0, v1, v2, v3);
- cleanupAfterGraphicsCall(false);
+ vertexAttribfImpl(index, 4, v0, v1, v2, v3);
}
-void WebGLRenderingContext::vertexAttrib4fv(unsigned long indx, Float32Array* v)
+void WebGLRenderingContext::vertexAttrib4fv(unsigned long index, Float32Array* v)
{
- // FIXME: Need to make sure array is big enough for attribute being set
- m_context->vertexAttrib4fv(indx, v->data());
- cleanupAfterGraphicsCall(false);
+ vertexAttribfvImpl(index, v, 4);
}
-void WebGLRenderingContext::vertexAttrib4fv(unsigned long indx, float* v, int size)
+void WebGLRenderingContext::vertexAttrib4fv(unsigned long index, float* v, int size)
{
- // FIXME: Need to make sure array is big enough for attribute being set
- UNUSED_PARAM(size);
-
- m_context->vertexAttrib4fv(indx, v);
- cleanupAfterGraphicsCall(false);
+ vertexAttribfvImpl(index, v, size, 4);
}
-void WebGLRenderingContext::vertexAttribPointer(unsigned long indx, long size, unsigned long type, bool normalized, unsigned long stride, unsigned long offset, ExceptionCode& ec)
+void WebGLRenderingContext::vertexAttribPointer(unsigned long index, long size, unsigned long type, bool normalized, long stride, long offset, ExceptionCode& ec)
{
- UNUSED_PARAM(ec);
- if (!m_boundArrayBuffer || indx >= m_maxVertexAttribs) {
+ if (index >= m_maxVertexAttribs) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return;
}
-
- if (indx >= m_vertexAttribState.size())
- m_vertexAttribState.resize(indx + 1);
-
+ if (size < 1 || size > 4 || stride < 0 || offset < 0) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ return;
+ }
+ if (!m_boundArrayBuffer) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return;
+ }
// Determine the number of elements the bound buffer can hold, given the offset, size, type and stride
long bytesPerElement = size * sizeInBytes(type, ec);
if (bytesPerElement <= 0)
return;
+
+ if (index >= m_vertexAttribState.size())
+ m_vertexAttribState.resize(index + 1);
+
long validatedStride = bytesPerElement;
if (stride != 0) {
if ((long) stride < bytesPerElement) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return;
}
-
validatedStride = stride;
}
-
- m_vertexAttribState[indx].bufferBinding = m_boundArrayBuffer;
- // Avoid off-by-one errors in numElements computation.
- // For the last element, we will only touch the data for the
- // element and nothing beyond it.
- long bytesRemaining = m_boundArrayBuffer->byteLength(GraphicsContext3D::ARRAY_BUFFER) - offset;
- if (bytesRemaining < bytesPerElement)
- m_vertexAttribState[indx].numElements = 0;
- else
- m_vertexAttribState[indx].numElements = 1 + (bytesRemaining - bytesPerElement) / validatedStride;
-
- m_context->vertexAttribPointer(indx, size, type, normalized, stride, offset);
+ m_vertexAttribState[index].bufferBinding = m_boundArrayBuffer;
+ m_vertexAttribState[index].bytesPerElement = bytesPerElement;
+ m_vertexAttribState[index].size = size;
+ m_vertexAttribState[index].type = type;
+ m_vertexAttribState[index].normalized = normalized;
+ m_vertexAttribState[index].stride = validatedStride;
+ m_vertexAttribState[index].originalStride = stride;
+ m_vertexAttribState[index].offset = offset;
+ m_context->vertexAttribPointer(index, size, type, normalized, stride, offset);
cleanupAfterGraphicsCall(false);
}
@@ -3141,6 +3082,18 @@ WebGLBuffer* WebGLRenderingContext::findBuffer(Platform3DObject obj)
return 0;
}
+WebGLShader* WebGLRenderingContext::findShader(Platform3DObject obj)
+{
+ if (!obj)
+ return 0;
+ HashSet<RefPtr<CanvasObject> >::iterator pend = m_canvasObjects.end();
+ for (HashSet<RefPtr<CanvasObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
+ if ((*it)->isShader() && (*it)->object() == obj)
+ return reinterpret_cast<WebGLShader*>((*it).get());
+ }
+ return 0;
+}
+
WebGLGetInfo WebGLRenderingContext::getBooleanParameter(unsigned long pname)
{
unsigned char value;
@@ -3148,6 +3101,20 @@ WebGLGetInfo WebGLRenderingContext::getBooleanParameter(unsigned long pname)
return WebGLGetInfo(static_cast<bool>(value));
}
+WebGLGetInfo WebGLRenderingContext::getBooleanArrayParameter(unsigned long pname)
+{
+ if (pname != GraphicsContext3D::COLOR_WRITEMASK) {
+ notImplemented();
+ return WebGLGetInfo(0, 0);
+ }
+ unsigned char value[4] = {0};
+ m_context->getBooleanv(pname, value);
+ bool boolValue[4];
+ for (int ii = 0; ii < 4; ++ii)
+ boolValue[ii] = static_cast<bool>(value[ii]);
+ return WebGLGetInfo(boolValue, 4);
+}
+
WebGLGetInfo WebGLRenderingContext::getFloatParameter(unsigned long pname)
{
float value;
@@ -3214,21 +3181,6 @@ WebGLGetInfo WebGLRenderingContext::getWebGLIntArrayParameter(unsigned long pnam
return WebGLGetInfo(Int32Array::create(value, length));
}
-WebGLGetInfo WebGLRenderingContext::getWebGLUnsignedByteArrayParameter(unsigned long pname)
-{
- unsigned char value[4] = {0};
- m_context->getBooleanv(pname, value);
- unsigned length = 0;
- switch (pname) {
- case GraphicsContext3D::COLOR_WRITEMASK:
- length = 4;
- break;
- default:
- notImplemented();
- }
- return WebGLGetInfo(Uint8Array::create(value, length));
-}
-
bool WebGLRenderingContext::isGLES2Compliant()
{
return m_context->isGLES2Compliant();
@@ -3236,8 +3188,6 @@ bool WebGLRenderingContext::isGLES2Compliant()
void WebGLRenderingContext::handleNPOTTextures(bool prepareToDraw)
{
- if (isGLES2Compliant())
- return;
bool resetActiveUnit = false;
for (unsigned ii = 0; ii < m_textureUnits.size(); ++ii) {
if (m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture()
@@ -3445,6 +3395,56 @@ bool WebGLRenderingContext::validateTexFuncParameters(unsigned long target, long
return true;
}
+bool WebGLRenderingContext::validateTexFuncData(long width, long height,
+ unsigned long format, unsigned long type,
+ ArrayBufferView* pixels)
+{
+ if (!pixels)
+ return true;
+
+ if (!validateTexFuncFormatAndType(format, type))
+ return false;
+
+ switch (type) {
+ case GraphicsContext3D::UNSIGNED_BYTE:
+ if (!pixels->isUnsignedByteArray()) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return false;
+ }
+ break;
+ case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
+ case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
+ case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
+ if (!pixels->isUnsignedShortArray()) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return false;
+ }
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ unsigned long componentsPerPixel, bytesPerComponent;
+ if (!m_context->computeFormatAndTypeParameters(format, type, &componentsPerPixel, &bytesPerComponent)) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
+ return false;
+ }
+
+ if (!width || !height)
+ return true;
+ unsigned int validRowBytes = width * componentsPerPixel * bytesPerComponent;
+ unsigned int totalRowBytes = validRowBytes;
+ unsigned int remainder = validRowBytes % m_unpackAlignment;
+ if (remainder)
+ totalRowBytes += (m_unpackAlignment - remainder);
+ unsigned int totalBytesRequired = (height - 1) * totalRowBytes + validRowBytes;
+ if (pixels->byteLength() < totalBytesRequired) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return false;
+ }
+ return true;
+}
+
bool WebGLRenderingContext::validateDrawMode(unsigned long mode)
{
switch (mode) {
@@ -3487,6 +3487,231 @@ bool WebGLRenderingContext::validateFramebufferFuncParameters(unsigned long targ
return true;
}
+bool WebGLRenderingContext::validateBlendEquation(unsigned long mode)
+{
+ switch (mode) {
+ case GraphicsContext3D::FUNC_ADD:
+ case GraphicsContext3D::FUNC_SUBTRACT:
+ case GraphicsContext3D::FUNC_REVERSE_SUBTRACT:
+ return true;
+ default:
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
+ return false;
+ }
+}
+
+bool WebGLRenderingContext::validateCapability(unsigned long cap)
+{
+ switch (cap) {
+ case GraphicsContext3D::BLEND:
+ case GraphicsContext3D::CULL_FACE:
+ case GraphicsContext3D::DEPTH_TEST:
+ case GraphicsContext3D::DITHER:
+ case GraphicsContext3D::POLYGON_OFFSET_FILL:
+ case GraphicsContext3D::SAMPLE_ALPHA_TO_COVERAGE:
+ case GraphicsContext3D::SAMPLE_COVERAGE:
+ case GraphicsContext3D::SCISSOR_TEST:
+ case GraphicsContext3D::STENCIL_TEST:
+ return true;
+ default:
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
+ return false;
+ }
+}
+
+bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, Float32Array* v, int requiredMinSize)
+{
+ if (!v) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ return false;
+ }
+ return validateUniformMatrixParameters(location, false, v->data(), v->length(), requiredMinSize);
+}
+
+bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, Int32Array* v, int requiredMinSize)
+{
+ if (!v) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ return false;
+ }
+ return validateUniformMatrixParameters(location, false, v->data(), v->length(), requiredMinSize);
+}
+
+bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, void* v, int size, int requiredMinSize)
+{
+ return validateUniformMatrixParameters(location, false, v, size, requiredMinSize);
+}
+
+bool WebGLRenderingContext::validateUniformMatrixParameters(const WebGLUniformLocation* location, bool transpose, Float32Array* v, int requiredMinSize)
+{
+ if (!v) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ return false;
+ }
+ return validateUniformMatrixParameters(location, transpose, v->data(), v->length(), requiredMinSize);
+}
+
+bool WebGLRenderingContext::validateUniformMatrixParameters(const WebGLUniformLocation* location, bool transpose, void* v, int size, int requiredMinSize)
+{
+ if (!location)
+ return false;
+ if (location->program() != m_currentProgram) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
+ return false;
+ }
+ if (!v) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ return false;
+ }
+ if (transpose) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ return false;
+ }
+ if (size < requiredMinSize) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ return false;
+ }
+ return true;
+}
+
+void WebGLRenderingContext::vertexAttribfImpl(unsigned long index, int expectedSize, float v0, float v1, float v2, float v3)
+{
+ if (index >= m_maxVertexAttribs) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ return;
+ }
+ // In GL, we skip setting vertexAttrib0 values.
+ if (index || isGLES2Compliant()) {
+ switch (expectedSize) {
+ case 1:
+ m_context->vertexAttrib1f(index, v0);
+ break;
+ case 2:
+ m_context->vertexAttrib2f(index, v0, v1);
+ break;
+ case 3:
+ m_context->vertexAttrib3f(index, v0, v1, v2);
+ break;
+ case 4:
+ m_context->vertexAttrib4f(index, v0, v1, v2, v3);
+ break;
+ }
+ cleanupAfterGraphicsCall(false);
+ }
+ if (index >= m_vertexAttribState.size())
+ m_vertexAttribState.resize(index + 1);
+ m_vertexAttribState[index].value[0] = v0;
+ m_vertexAttribState[index].value[1] = v1;
+ m_vertexAttribState[index].value[2] = v2;
+ m_vertexAttribState[index].value[3] = v3;
+}
+
+void WebGLRenderingContext::vertexAttribfvImpl(unsigned long index, Float32Array* v, int expectedSize)
+{
+ if (!v) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ return;
+ }
+ vertexAttribfvImpl(index, v->data(), v->length(), expectedSize);
+}
+
+void WebGLRenderingContext::vertexAttribfvImpl(unsigned long index, float* v, int size, int expectedSize)
+{
+ if (!v) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ return;
+ }
+ if (size < expectedSize) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ return;
+ }
+ if (index >= m_maxVertexAttribs) {
+ m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
+ return;
+ }
+ // In GL, we skip setting vertexAttrib0 values.
+ if (index || isGLES2Compliant()) {
+ switch (expectedSize) {
+ case 1:
+ m_context->vertexAttrib1fv(index, v);
+ break;
+ case 2:
+ m_context->vertexAttrib2fv(index, v);
+ break;
+ case 3:
+ m_context->vertexAttrib3fv(index, v);
+ break;
+ case 4:
+ m_context->vertexAttrib4fv(index, v);
+ break;
+ }
+ cleanupAfterGraphicsCall(false);
+ }
+ if (index >= m_vertexAttribState.size())
+ m_vertexAttribState.resize(index + 1);
+ m_vertexAttribState[index].initValue();
+ for (int ii = 0; ii < expectedSize; ++ii)
+ m_vertexAttribState[index].value[ii] = v[ii];
+}
+
+void WebGLRenderingContext::initVertexAttrib0()
+{
+ m_vertexAttribState.resize(1);
+ m_vertexAttrib0Buffer = createBuffer();
+ m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer.get());
+ m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, 0, GraphicsContext3D::DYNAMIC_DRAW);
+ m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, false, 0, 0);
+ m_vertexAttribState[0].bufferBinding = m_vertexAttrib0Buffer;
+ m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0);
+ m_context->enableVertexAttribArray(0);
+ m_vertexAttrib0BufferSize = 0;
+ m_vertexAttrib0BufferValue[0] = 0.0f;
+ m_vertexAttrib0BufferValue[1] = 0.0f;
+ m_vertexAttrib0BufferValue[2] = 0.0f;
+ m_vertexAttrib0BufferValue[3] = 1.0f;
+}
+
+bool WebGLRenderingContext::simulateVertexAttrib0(long numVertex)
+{
+ const VertexAttribState& state = m_vertexAttribState[0];
+ if (state.enabled || !m_currentProgram || !m_currentProgram->object()
+ || !m_currentProgram->isUsingVertexAttrib0())
+ return false;
+ m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer.get());
+ long bufferDataSize = (numVertex + 1) * 4 * sizeof(float);
+ if (bufferDataSize > m_vertexAttrib0BufferSize
+ || state.value[0] != m_vertexAttrib0BufferValue[0]
+ || state.value[1] != m_vertexAttrib0BufferValue[1]
+ || state.value[2] != m_vertexAttrib0BufferValue[2]
+ || state.value[3] != m_vertexAttrib0BufferValue[3]) {
+ RefPtr<Float32Array> bufferData = Float32Array::create((numVertex + 1) * 4);
+ for (long ii = 0; ii < numVertex + 1; ++ii) {
+ bufferData->set(ii * 4, state.value[0]);
+ bufferData->set(ii * 4 + 1, state.value[1]);
+ bufferData->set(ii * 4 + 2, state.value[2]);
+ bufferData->set(ii * 4 + 3, state.value[3]);
+ }
+ m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, bufferData.get(), GraphicsContext3D::DYNAMIC_DRAW);
+ m_vertexAttrib0BufferSize = bufferDataSize;
+ m_vertexAttrib0BufferValue[0] = state.value[0];
+ m_vertexAttrib0BufferValue[1] = state.value[1];
+ m_vertexAttrib0BufferValue[2] = state.value[2];
+ m_vertexAttrib0BufferValue[3] = state.value[3];
+ }
+ m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, false, 0, 0);
+ return true;
+}
+
+void WebGLRenderingContext::restoreStatesAfterVertexAttrib0Simulation()
+{
+ const VertexAttribState& state = m_vertexAttribState[0];
+ if (state.bufferBinding != m_vertexAttrib0Buffer) {
+ m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, state.bufferBinding.get());
+ m_context->vertexAttribPointer(0, state.size, state.type, state.normalized, state.originalStride, state.offset);
+ }
+ m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_boundArrayBuffer.get());
+}
+
} // namespace WebCore
#endif // ENABLE(3D_CANVAS)
diff --git a/WebCore/html/canvas/WebGLRenderingContext.h b/WebCore/html/canvas/WebGLRenderingContext.h
index d05d60b..be74001 100644
--- a/WebCore/html/canvas/WebGLRenderingContext.h
+++ b/WebCore/html/canvas/WebGLRenderingContext.h
@@ -131,6 +131,8 @@ class WebKitCSSMatrix;
PassRefPtr<WebGLActiveInfo> getActiveAttrib(WebGLProgram*, unsigned long index, ExceptionCode&);
PassRefPtr<WebGLActiveInfo> getActiveUniform(WebGLProgram*, unsigned long index, ExceptionCode&);
+ bool getAttachedShaders(WebGLProgram*, Vector<WebGLShader*>&, ExceptionCode&);
+
int getAttribLocation(WebGLProgram*, const String& name);
WebGLGetInfo getBufferParameter(unsigned long target, unsigned long pname, ExceptionCode&);
@@ -281,20 +283,20 @@ class WebKitCSSMatrix;
void useProgram(WebGLProgram*, ExceptionCode&);
void validateProgram(WebGLProgram*, ExceptionCode&);
- void vertexAttrib1f(unsigned long indx, float x);
- void vertexAttrib1fv(unsigned long indx, Float32Array* values);
- void vertexAttrib1fv(unsigned long indx, float* values, int size);
- void vertexAttrib2f(unsigned long indx, float x, float y);
- void vertexAttrib2fv(unsigned long indx, Float32Array* values);
- void vertexAttrib2fv(unsigned long indx, float* values, int size);
- void vertexAttrib3f(unsigned long indx, float x, float y, float z);
- void vertexAttrib3fv(unsigned long indx, Float32Array* values);
- void vertexAttrib3fv(unsigned long indx, float* values, int size);
- void vertexAttrib4f(unsigned long indx, float x, float y, float z, float w);
- void vertexAttrib4fv(unsigned long indx, Float32Array* values);
- void vertexAttrib4fv(unsigned long indx, float* values, int size);
- void vertexAttribPointer(unsigned long indx, long size, unsigned long type, bool normalized,
- unsigned long stride, unsigned long offset, ExceptionCode&);
+ void vertexAttrib1f(unsigned long index, float x);
+ void vertexAttrib1fv(unsigned long index, Float32Array* values);
+ void vertexAttrib1fv(unsigned long index, float* values, int size);
+ void vertexAttrib2f(unsigned long index, float x, float y);
+ void vertexAttrib2fv(unsigned long index, Float32Array* values);
+ void vertexAttrib2fv(unsigned long index, float* values, int size);
+ void vertexAttrib3f(unsigned long index, float x, float y, float z);
+ void vertexAttrib3fv(unsigned long index, Float32Array* values);
+ void vertexAttrib3fv(unsigned long index, float* values, int size);
+ void vertexAttrib4f(unsigned long index, float x, float y, float z, float w);
+ void vertexAttrib4fv(unsigned long index, Float32Array* values);
+ void vertexAttrib4fv(unsigned long index, float* values, int size);
+ void vertexAttribPointer(unsigned long index, long size, unsigned long type, bool normalized,
+ long stride, long offset, ExceptionCode&);
void viewport(long x, long y, unsigned long width, unsigned long height);
@@ -318,6 +320,7 @@ class WebKitCSSMatrix;
WebGLTexture* findTexture(Platform3DObject);
WebGLRenderbuffer* findRenderbuffer(Platform3DObject);
WebGLBuffer* findBuffer(Platform3DObject);
+ WebGLShader* findShader(Platform3DObject);
void markContextChanged();
void cleanupAfterGraphicsCall(bool changed)
@@ -354,14 +357,44 @@ class WebKitCSSMatrix;
// Cached values for vertex attrib range checks
class VertexAttribState {
public:
- VertexAttribState() : enabled(false), numElements(0) { }
+ VertexAttribState()
+ : enabled(false)
+ , bytesPerElement(0)
+ , size(4)
+ , type(GraphicsContext3D::FLOAT)
+ , normalized(false)
+ , stride(16)
+ , originalStride(0)
+ , offset(0)
+ {
+ initValue();
+ }
+
+ void initValue()
+ {
+ value[0] = 0.0f;
+ value[1] = 0.0f;
+ value[2] = 0.0f;
+ value[3] = 1.0f;
+ }
+
bool enabled;
- long numElements;
RefPtr<WebGLBuffer> bufferBinding;
+ long bytesPerElement;
+ long size;
+ unsigned long type;
+ bool normalized;
+ long stride;
+ long originalStride;
+ long offset;
+ float value[4];
};
Vector<VertexAttribState> m_vertexAttribState;
unsigned m_maxVertexAttribs;
+ RefPtr<WebGLBuffer> m_vertexAttrib0Buffer;
+ long m_vertexAttrib0BufferSize;
+ float m_vertexAttrib0BufferValue[4];
RefPtr<WebGLProgram> m_currentProgram;
RefPtr<WebGLFramebuffer> m_framebufferBinding;
@@ -389,13 +422,13 @@ class WebKitCSSMatrix;
// Helpers for getParameter and others
WebGLGetInfo getBooleanParameter(unsigned long pname);
+ WebGLGetInfo getBooleanArrayParameter(unsigned long pname);
WebGLGetInfo getFloatParameter(unsigned long pname);
WebGLGetInfo getIntParameter(unsigned long pname);
WebGLGetInfo getLongParameter(unsigned long pname);
WebGLGetInfo getUnsignedLongParameter(unsigned long pname);
WebGLGetInfo getWebGLFloatArrayParameter(unsigned long pname);
WebGLGetInfo getWebGLIntArrayParameter(unsigned long pname);
- WebGLGetInfo getWebGLUnsignedByteArrayParameter(unsigned long pname);
void texImage2DBase(unsigned target, unsigned level, unsigned internalformat,
unsigned width, unsigned height, unsigned border,
@@ -424,16 +457,23 @@ class WebKitCSSMatrix;
WebGLTexture* getTextureBinding(unsigned long target);
// Helper function to check input format/type for functions {copy}Tex{Sub}Image.
- // Generate GL error and return false if parameters are invalid.
+ // Generates GL error and returns false if parameters are invalid.
bool validateTexFuncFormatAndType(unsigned long format, unsigned long type);
// Helper function to check input parameters for functions {copy}Tex{Sub}Image.
- // Generate GL error and return false if parameters are invalid.
+ // Generates GL error and returns false if parameters are invalid.
bool validateTexFuncParameters(unsigned long target, long level,
unsigned long internalformat,
long width, long height, long border,
unsigned long format, unsigned long type);
+ // Helper function to validate that the given ArrayBufferView
+ // is of the correct type and contains enough data for the texImage call.
+ // Generates GL error and returns false if parameters are invalid.
+ bool validateTexFuncData(long width, long height,
+ unsigned long format, unsigned long type,
+ ArrayBufferView* pixels);
+
// Helper function to validate mode for draw{Arrays/Elements}.
bool validateDrawMode(unsigned long);
@@ -448,6 +488,29 @@ class WebKitCSSMatrix;
// Generate GL error if parameters are illegal.
bool validateFramebufferFuncParameters(unsigned long target, unsigned long attachment);
+ // Helper function to validate blend equation mode.
+ bool validateBlendEquation(unsigned long);
+
+ // Helper function to validate a GL capability.
+ bool validateCapability(unsigned long);
+
+ // Helper function to validate input parameters for uniform functions.
+ bool validateUniformParameters(const WebGLUniformLocation* location, Float32Array* v, int mod);
+ bool validateUniformParameters(const WebGLUniformLocation* location, Int32Array* v, int mod);
+ bool validateUniformParameters(const WebGLUniformLocation* location, void* v, int size, int mod);
+ bool validateUniformMatrixParameters(const WebGLUniformLocation* location, bool transpose, Float32Array* v, int mod);
+ bool validateUniformMatrixParameters(const WebGLUniformLocation* location, bool transpose, void* v, int size, int mod);
+
+ // Helper functions for vertexAttribNf{v}.
+ void vertexAttribfImpl(unsigned long index, int expectedSize, float v0, float v1, float v2, float v3);
+ void vertexAttribfvImpl(unsigned long index, Float32Array* v, int expectedSize);
+ void vertexAttribfvImpl(unsigned long index, float* v, int size, int expectedSize);
+
+ // Helpers for simulating vertexAttrib0
+ void initVertexAttrib0();
+ bool simulateVertexAttrib0(long numVertex);
+ void restoreStatesAfterVertexAttrib0Simulation();
+
friend class WebGLStateRestorer;
};
diff --git a/WebCore/html/canvas/WebGLRenderingContext.idl b/WebCore/html/canvas/WebGLRenderingContext.idl
index b3793f5..1ea4c6d 100644
--- a/WebCore/html/canvas/WebGLRenderingContext.idl
+++ b/WebCore/html/canvas/WebGLRenderingContext.idl
@@ -536,7 +536,9 @@ module html {
WebGLActiveInfo getActiveUniform(in WebGLProgram program, in unsigned long index)
raises (DOMException);
- // WebGLShaderArray glGetAttachedShaders(GLuint program);
+ // Array getAttachedShaders(GLuint program) raises (DOMException);
+ [Custom] void getAttachedShaders(GLuint program)
+ raises (DOMException);
int getAttribLocation(in WebGLProgram program, in DOMString name);
diff --git a/WebCore/html/canvas/WebGLShader.cpp b/WebCore/html/canvas/WebGLShader.cpp
index a353b15..664d3cb 100644
--- a/WebCore/html/canvas/WebGLShader.cpp
+++ b/WebCore/html/canvas/WebGLShader.cpp
@@ -39,6 +39,7 @@ PassRefPtr<WebGLShader> WebGLShader::create(WebGLRenderingContext* ctx, Graphics
WebGLShader::WebGLShader(WebGLRenderingContext* ctx, GraphicsContext3D::WebGLEnumType type)
: CanvasObject(ctx)
+ , m_type(type)
{
setObject(context()->graphicsContext3D()->createShader(type));
}
diff --git a/WebCore/html/canvas/WebGLShader.h b/WebCore/html/canvas/WebGLShader.h
index d4006aa..a0daa59 100644
--- a/WebCore/html/canvas/WebGLShader.h
+++ b/WebCore/html/canvas/WebGLShader.h
@@ -39,12 +39,16 @@ namespace WebCore {
static PassRefPtr<WebGLShader> create(WebGLRenderingContext*, GraphicsContext3D::WebGLEnumType);
+ GraphicsContext3D::WebGLEnumType getType() const { return m_type; }
+
private:
WebGLShader(WebGLRenderingContext*, GraphicsContext3D::WebGLEnumType);
virtual void _deleteObject(Platform3DObject);
virtual bool isShader() const { return true; }
+
+ GraphicsContext3D::WebGLEnumType m_type;
};
} // namespace WebCore