Typed arrays implementation that supports use in shared code and emulation of missing pieces where necessary.

Public review at http://gwt-code-reviews.appspot.com/1626803/
Inspired by http://gwt-code-reviews.appspot.com/1621803/
Review by: tbroyer, pdr, steffen.schafer, jgw, fredsa
Issues: 2815, 7100


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10839 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/eclipse/lang/.classpath b/eclipse/lang/.classpath
index 9d67ef8..4dc55c0 100644
--- a/eclipse/lang/.classpath
+++ b/eclipse/lang/.classpath
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
 	<classpathentry kind="src" path="dev/super/com/google/gwt/dev/jjs/intrinsic"/>
+	<classpathentry kind="src" path="user/super/com/google/gwt/typedarrays/super"/>
 	<classpathentry kind="src" path="user/src/com/google/gwt/regexp/super"/>
 	<classpathentry kind="src" path="user/super/com/google/gwt/user/translatable"/>
 	<classpathentry kind="src" path="user/super/com/google/gwt/benchmarks/translatable"/>
diff --git a/tools/api-checker/config/gwt23_24userApi.conf b/tools/api-checker/config/gwt23_24userApi.conf
index 85bffeb..8366905 100644
--- a/tools/api-checker/config/gwt23_24userApi.conf
+++ b/tools/api-checker/config/gwt23_24userApi.conf
@@ -38,6 +38,7 @@
 :com/google/gwt/dev/shell/**\
 :com/google/gwt/dev/ui/**\
 :com/google/gwt/dev/util/**\
+:com/google/gwt/i18n/**/impl/cldr/**\
 :com/google/gwt/junit/*.java\
 :com/google/gwt/junit/client/GWTTestCase.java\
 :com/google/gwt/junit/client/impl/GWTRunner.java\
@@ -81,6 +82,7 @@
 excludedFiles_new user/src/com/google/gwt/benchmarks/BenchmarkReport.java\
 :user/src/com/google/gwt/benchmarks/BenchmarkShell.java\
 :user/src/com/google/gwt/benchmarks/client/Benchmark.java\
+:user/super/com/google/gwt/typedarrays/super/com/google/gwt/typedarrays/shared/TypedArraysFactory.java\
 :**/linker/**\
 :**/rebind/**\
 :**/server/**\
@@ -90,6 +92,7 @@
 :user/src/com/google/web/bindery/autobean/shared/ValueCodexHelper.java\
 :user/src/com/google/web/bindery/autobean/**/impl/**\
 :user/src/com/google/gwt/core/client/impl/WeakMapping.java\
+:user/src/com/google/gwt/i18n/**/impl/cldr/**\
 :user/src/com/google/gwt/junit/*.java\
 :user/src/com/google/gwt/junit/client/GWTTestCase.java\
 :user/src/com/google/gwt/junit/client/impl/GWTRunner.java\
@@ -126,6 +129,7 @@
 :com.google.gwt.junit.client.impl\
 :com.google.gwt.benchmarks.client.impl\
 :com.google.gwt.user.client.ui.impl\
+:com.google.gwt.i18n.client.impl\
 
 ##############################################
 #Api  whitelist
@@ -208,3 +212,14 @@
 com.google.gwt.logging.impl.LevelImplRegular::severe() MISSING
 com.google.gwt.logging.impl.LevelImplRegular::warning() MISSING
 java.util.logging.Level::Level(Ljava/lang/String;I) MISSING
+
+# implementation details shouldn't have been considered part of the API anyway
+com.google.gwt.core.client.impl.CrossSiteIframeLoadingStrategy MISSING
+com.google.gwt.core.client.impl.XhrLoadingStrategy.RequestData MISSING
+com.google.gwt.core.client.impl.XhrLoadingStrategy::createXhr() MISSING
+com.google.gwt.core.client.impl.XhrLoadingStrategy::onLoadError(Lcom/google/gwt/core/client/impl/XhrLoadingStrategy$RequestData;Ljava/lang/Throwable;Z) MISSING
+com.google.gwt.core.client.impl.XhrLoadingStrategy::tryLoad(Lcom/google/gwt/core/client/impl/XhrLoadingStrategy$RequestData;) MISSING
+com.google.gwt.i18n.client.impl.DateRecord MISSING
+
+# moved from user package to useragent, not expected to be used directly
+com.google.gwt.user.client.UserAgentAsserter MISSING
diff --git a/user/src/com/google/gwt/core/Core.gwt.xml b/user/src/com/google/gwt/core/Core.gwt.xml
index f0f0bf7..85e3a25 100644
--- a/user/src/com/google/gwt/core/Core.gwt.xml
+++ b/user/src/com/google/gwt/core/Core.gwt.xml
@@ -20,6 +20,7 @@
 <module>
   <inherits name="com.google.gwt.dev.jjs.intrinsic.Intrinsic" />
   <inherits name="com.google.gwt.emul.Emulation" />
+  <inherits name="com.google.gwt.typedarrays.TypedArrays" />
   <inherits name="com.google.gwt.xhr.XMLHttpRequest" />
   <inherits name="com.google.gwt.core.CompilerParameters" />
   <inherits name="com.google.gwt.core.EmulateJsStack" />
diff --git a/user/src/com/google/gwt/core/CoreWithUserAgent.gwt.xml b/user/src/com/google/gwt/core/CoreWithUserAgent.gwt.xml
index 3384a1b..f3b8dc5 100644
--- a/user/src/com/google/gwt/core/CoreWithUserAgent.gwt.xml
+++ b/user/src/com/google/gwt/core/CoreWithUserAgent.gwt.xml
@@ -15,6 +15,9 @@
 <!-- Deferred binding rules for core classes based on user agent. -->
 <module>
   <inherits name="com.google.gwt.core.Core"/>
+  <inherits name="com.google.gwt.core.CompilerParameters" />
+  <inherits name="com.google.gwt.core.EmulateJsStack" />
+  <inherits name="com.google.gwt.useragent.UserAgent"/>
 
   <replace-with class="com.google.gwt.core.client.impl.StackTraceCreator.CollectorChrome">
     <when-type-is class="com.google.gwt.core.client.impl.StackTraceCreator.Collector" />
@@ -37,7 +40,7 @@
       <when-property-is name="user.agent" value="opera" />
     </any>
   </replace-with>
-  
+
   <replace-with
       class="com.google.gwt.core.client.impl.StackTraceCreator.CollectorNull">
     <when-type-is class="com.google.gwt.core.client.impl.StackTraceCreator.Collector" />
diff --git a/user/src/com/google/gwt/core/client/JsArrayUtils.java b/user/src/com/google/gwt/core/client/JsArrayUtils.java
new file mode 100644
index 0000000..3eedec0
--- /dev/null
+++ b/user/src/com/google/gwt/core/client/JsArrayUtils.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.core.client;
+
+/**
+ * Utility class for manipulating JS arrays.  These methods are not on other
+ * JavaScriptObject subclasses, such as JsArray, because adding new methods might
+ * break existing subtypes.
+ */
+public class JsArrayUtils {
+
+  /**
+   * Take a Java array, and produce a JS array that is only used for reading.  As
+   * this is actually a reference to the original array in prod mode, the source
+   * must not be modified while this copy is in use or you will get different
+   * behavior between DevMode and prod mode.
+   * 
+   * @param array source array
+   * @return JS array, which may be a copy or an alias of the input array
+   */
+  public static JsArrayInteger readOnlyJsArray(byte[] array) {
+    if (GWT.isScript()) {
+      return arrayAsJsArrayForProdMode(array).cast();
+    }
+    JsArrayInteger dest = JsArrayInteger.createArray().cast();
+    for (int i = 0; i < array.length; ++i) {
+      dest.push(array[i]);
+    }
+    return dest;
+  }
+
+  /**
+   * Take a Java array, and produce a JS array that is only used for reading.  As
+   * this is actually a reference to the original array in prod mode, the source
+   * must not be modified while this copy is in use or you will get different
+   * behavior between DevMode and prod mode.
+   * 
+   * @param array source array
+   * @return JS array, which may be a copy or an alias of the input array
+   */
+  public static JsArrayNumber readOnlyJsArray(double[] array) {
+    if (GWT.isScript()) {
+      return arrayAsJsArrayForProdMode(array).cast();
+    }
+    JsArrayNumber dest = JsArrayNumber.createArray().cast();
+    for (int i = 0; i < array.length; ++i) {
+      dest.push(array[i]);
+    }
+    return dest;
+  }
+
+  /**
+   * Take a Java array, and produce a JS array that is only used for reading.  As
+   * this is actually a reference to the original array in prod mode, the source
+   * must not be modified while this copy is in use or you will get different
+   * behavior between DevMode and prod mode.
+   * 
+   * @param array source array
+   * @return JS array, which may be a copy or an alias of the input array
+   */
+  public static JsArrayNumber readOnlyJsArray(float[] array) {
+    if (GWT.isScript()) {
+      return arrayAsJsArrayForProdMode(array).cast();
+    }
+    JsArrayNumber dest = JsArrayNumber.createArray().cast();
+    for (int i = 0; i < array.length; ++i) {
+      dest.push(array[i]);
+    }
+    return dest;
+  }
+
+  /**
+   * Take a Java array, and produce a JS array that is only used for reading.  As
+   * this is actually a reference to the original array in prod mode, the source
+   * must not be modified while this copy is in use or you will get different
+   * behavior between DevMode and prod mode.
+   * 
+   * @param array source array
+   * @return JS array, which may be a copy or an alias of the input array
+   */
+  public static JsArrayInteger readOnlyJsArray(int[] array) {
+    if (GWT.isScript()) {
+      return arrayAsJsArrayForProdMode(array).cast();
+    }
+    JsArrayInteger dest = JsArrayInteger.createArray().cast();
+    for (int i = 0; i < array.length; ++i) {
+      dest.push(array[i]);
+    }
+    return dest;
+  }
+
+  /**
+   * Take a Java array, and produce a JS array that is only used for reading.  As
+   * this is actually a reference to the original array in prod mode, the source
+   * must not be modified while this copy is in use or you will get different
+   * behavior between DevMode and prod mode.
+   * <p>
+   * <b>NOTE: long values are not supported in JS, so long emulation is slow
+   * and this method assumes that all the values can be safely stored in a
+   * double.</b>
+   * 
+   * @param array source array - its values are assumed to be in the valid range
+   *     for doubles -- if the values exceed 2^53, low-order bits will be lost
+   * @return JS array, which may be a copy or an alias of the input array
+   */
+  public static JsArrayNumber readOnlyJsArray(long[] array) {
+    if (GWT.isScript()) {
+      return arrayAsJsArrayForProdMode(array).cast();
+    }
+    JsArrayNumber dest = JsArrayNumber.createArray().cast();
+    for (int i = 0; i < array.length; ++i) {
+      dest.push(array[i]);
+    }
+    return dest;
+  }
+
+  /**
+   * Take a Java array, and produce a JS array that is only used for reading.  As
+   * this is actually a reference to the original array in prod mode, the source
+   * must not be modified while this copy is in use or you will get different
+   * behavior between DevMode and prod mode.
+   * 
+   * @param array source array
+   * @return JS array, which may be a copy or an alias of the input array
+   */
+  public static JsArrayInteger readOnlyJsArray(short[] array) {
+    if (GWT.isScript()) {
+      return arrayAsJsArrayForProdMode(array).cast();
+    }
+    JsArrayInteger dest = JsArrayInteger.createArray().cast();
+    for (int i = 0; i < array.length; ++i) {
+      dest.push(array[i]);
+    }
+    return dest;
+  }
+
+  /**
+   * Take a Java array, and produce a JS array that is only used for reading.  As
+   * this is actually a reference to the original array in prod mode, the source
+   * must not be modified while this copy is in use or you will get different
+   * behavior between DevMode and prod mode.
+   * 
+   * @param array source array
+   * @return JS array, which may be a copy or an alias of the input array
+   */
+  public static <T extends JavaScriptObject> JsArray<T> readOnlyJsArray(T[] array) {
+    if (GWT.isScript()) {
+      return arrayAsJsArrayForProdMode(array).cast();
+    }
+    JsArray<T> dest = JavaScriptObject.createArray().cast();
+    for (int i = 0; i < array.length; ++i) {
+      dest.push(array[i]);
+    }
+    return dest;
+  }
+
+  /**
+   * In production mode, Java arrays really are JS arrays, so just return it.
+   * 
+   * @param array must be a Java array of some type
+   * @return a JavaScriptObject, which should be used as the appropriate type of
+   *     JS array depending on the input array type
+   */
+  private static native JavaScriptObject arrayAsJsArrayForProdMode(Object array) /*-{
+    return array;
+  }-*/;
+
+  private JsArrayUtils() {
+  }
+
+}
diff --git a/user/src/com/google/gwt/typedarrays/TypedArrays.gwt.xml b/user/src/com/google/gwt/typedarrays/TypedArrays.gwt.xml
new file mode 100644
index 0000000..9f6a137
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/TypedArrays.gwt.xml
@@ -0,0 +1,60 @@
+<!--                                                                        -->
+<!-- Copyright 2012 Google Inc.                                             -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you    -->
+<!-- may not use this file except in compliance with the License. You may   -->
+<!-- may obtain a copy of the License at                                    -->
+<!--                                                                        -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0                             -->
+<!--                                                                        -->
+<!-- Unless required by applicable law or agreed to in writing, software    -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS,      -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        -->
+<!-- implied. License for the specific language governing permissions and   -->
+<!-- limitations under the License.                                         -->
+
+<!-- Support for typed arrays.                                              -->
+<module>
+  <inherits name="com.google.gwt.core.Core" />
+  <inherits name="com.google.gwt.useragent.UserAgent"/>
+
+  <source path="client" />
+  <source path="shared" />
+  <super-source path="super" />
+
+  <!-- IE10+ will support typed arrays, but not before then -->
+  <replace-with class="com.google.gwt.typedarrays.client.NoSupportImpl">
+    <when-type-is class="com.google.gwt.typedarrays.client.NativeImpl"/>
+    <any>
+      <when-property-is name="user.agent" value="ie6"/>
+      <when-property-is name="user.agent" value="ie8"/>
+      <when-property-is name="user.agent" value="ie9"/>
+    </any>
+  </replace-with>
+
+  <!-- WebKit, Opera 11.6+ support DataView but not Uint8ClampedArray -->
+  <replace-with class="com.google.gwt.typedarrays.client.NativeImplEmulClamped">
+    <when-type-is class="com.google.gwt.typedarrays.client.NativeImpl"/>
+    <any>
+      <when-property-is name="user.agent" value="safari"/>
+      <when-property-is name="user.agent" value="opera"/>
+    </any>
+  </replace-with>
+
+  <!-- FireFox supports Uint8ClampedArray but not DataView -->
+  <replace-with class="com.google.gwt.typedarrays.client.NativeImplEmulDataView">
+    <when-type-is class="com.google.gwt.typedarrays.client.NativeImpl"/>
+    <any>
+      <when-property-is name="user.agent" value="gecko1_8"/>
+    </any>
+  </replace-with>
+
+  <!-- IE10 or future FF/WebKit may go here -->
+  <replace-with class="com.google.gwt.typedarrays.client.NativeImplFull">
+    <when-type-is class="com.google.gwt.typedarrays.client.NativeImpl"/>
+    <any>
+    </any>
+  </replace-with>
+
+  <!-- TODO: other optimized versions? -->
+</module>
+
diff --git a/user/src/com/google/gwt/typedarrays/client/ArrayBufferNative.java b/user/src/com/google/gwt/typedarrays/client/ArrayBufferNative.java
new file mode 100644
index 0000000..db2603d
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/ArrayBufferNative.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+
+/**
+ * JS native implementation of {@link ArrayBuffer}.
+ */
+public final class ArrayBufferNative extends JavaScriptObject implements ArrayBuffer {
+
+  /**
+   * @param length
+   * @return an {@link ArrayBuffer} instance
+   */
+  public static native ArrayBufferNative create(int length) /*-{
+    return new ArrayBuffer(length);
+  }-*/;
+
+  protected ArrayBufferNative() {
+  }
+
+  @Override
+  public native int byteLength() /*-{
+    return this.byteLength;
+  }-*/;
+}
diff --git a/user/src/com/google/gwt/typedarrays/client/ArrayBufferViewNative.java b/user/src/com/google/gwt/typedarrays/client/ArrayBufferViewNative.java
new file mode 100644
index 0000000..4d53766
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/ArrayBufferViewNative.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.ArrayBufferView;
+
+/**
+ * Base class for JS implementation of various views.
+ */
+public class ArrayBufferViewNative extends JavaScriptObject implements ArrayBufferView {
+
+  protected ArrayBufferViewNative() {
+  }
+
+  @Override
+  public final native ArrayBuffer buffer() /*-{
+    return this.buffer;
+  }-*/;
+
+  @Override
+  public final native int byteLength() /*-{
+    return this.byteLength;
+  }-*/;
+
+  @Override
+  public final native int byteOffset() /*-{
+    return this.byteOffset;
+  }-*/;
+}
diff --git a/user/src/com/google/gwt/typedarrays/client/DataViewNative.java b/user/src/com/google/gwt/typedarrays/client/DataViewNative.java
new file mode 100644
index 0000000..c8baa9d
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/DataViewNative.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.DataView;
+
+/**
+ * JS native implementation of {@link DataView}.
+ */
+public final class DataViewNative extends ArrayBufferViewNative implements DataView {
+
+  /**
+   * @param buffer
+   * @return a {@link DataView} instance
+   */
+  public static native DataView create(ArrayBuffer buffer) /*-{
+    return new DataView(buffer);
+  }-*/;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @return a {@link DataView} instance
+   */
+  public static native DataView create(ArrayBuffer buffer, int byteOffset) /*-{
+    return new DataView(buffer, byteOffset);
+  }-*/;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param byteLength
+   * @return a {@link DataView} instance
+   */
+  public static native DataView create(ArrayBuffer buffer, int byteOffset,
+      int byteLength) /*-{
+    return new DataView(buffer, byteOffset, byteLength);
+  }-*/;
+
+  protected DataViewNative() {
+  }
+
+  @Override
+  public native float getFloat32(int byteOffset) /*-{
+    return this.getFloat32(byteOffset);
+  }-*/;
+
+  @Override
+  public native float getFloat32(int byteOffset, boolean littleEndian) /*-{
+    return this.getFloat32(byteOffset, littleEndian);
+  }-*/;
+
+  @Override
+  public native double getFloat64(int byteOffset) /*-{
+    return this.getFloat64(byteOffset);
+  }-*/;
+
+  @Override
+  public native double getFloat64(int byteOffset, boolean littleEndian) /*-{
+    return this.getFloat64(byteOffset, littleEndian);
+  }-*/;
+
+  @Override
+  public native short getInt16(int byteOffset) /*-{
+    return this.getInt16(byteOffset);
+  }-*/;
+
+  @Override
+  public native short getInt16(int byteOffset, boolean littleEndian) /*-{
+    return this.getInt16(byteOffset, littleEndian);
+  }-*/;
+
+  @Override
+  public native int getInt32(int byteOffset) /*-{
+    return this.getInt32(byteOffset);
+  }-*/;
+
+  @Override
+  public native int getInt32(int byteOffset, boolean littleEndian) /*-{
+    return this.getInt32(byteOffset, littleEndian);
+  }-*/;
+
+  @Override
+  public native byte getInt8(int byteOffset) /*-{
+    return this.getInt8(byteOffset);
+  }-*/;
+
+  @Override
+  public native int getUint16(int byteOffset) /*-{
+    return this.getUint16(byteOffset);
+  }-*/;
+
+  @Override
+  public native int getUint16(int byteOffset, boolean littleEndian) /*-{
+    return this.getUint16(byteOffset, littleEndian);
+  }-*/;
+
+  @Override
+  public long getUint32(int byteOffset) {
+    return (long) getUint32AsDouble(byteOffset);
+  }
+
+  @Override
+  public long getUint32(int byteOffset, boolean littleEndian) {
+    return (long) getUint32AsDouble(byteOffset, littleEndian);
+  }
+
+  @Override
+  public native double getUint32AsDouble(int byteOffset) /*-{
+    return this.getUint32(byteOffset);
+  }-*/;
+
+  @Override
+  public native double getUint32AsDouble(int byteOffset, boolean littleEndian) /*-{
+    return this.getUint32(byteOffset, littleEndian);
+  }-*/;
+
+  @Override
+  public native short getUint8(int byteOffset) /*-{
+    return this.getUint8(byteOffset);
+  }-*/;
+
+  @Override
+  public native void setFloat32(int byteOffset, float value) /*-{
+    this.setFloat32(byteOffset, value);
+  }-*/;
+
+  @Override
+  public native void setFloat32(int byteOffset, float value, boolean littleEndian) /*-{
+    this.setFloat32(byteOffset, value, littleEndian);
+  }-*/;
+
+  @Override
+  public native void setFloat64(int byteOffset, double value) /*-{
+    this.setFloat64(byteOffset, value);
+  }-*/;
+
+  @Override
+  public native void setFloat64(int byteOffset, double value, boolean littleEndian) /*-{
+    this.setFloat64(byteOffset, value, littleEndian);
+  }-*/;
+
+  @Override
+  public native void setInt16(int byteOffset, int value) /*-{
+    this.setInt16(byteOffset, value);
+  }-*/;
+
+  @Override
+  public native void setInt16(int byteOffset, int value, boolean littleEndian) /*-{
+    this.setInt16(byteOffset, value, littleEndian);
+  }-*/;
+
+  @Override
+  public native void setInt32(int byteOffset, int value) /*-{
+    this.setInt32(byteOffset, value);
+  }-*/;
+
+  @Override
+  public native void setInt32(int byteOffset, int value, boolean littleEndian) /*-{
+    this.setInt32(byteOffset, value, littleEndian);
+  }-*/;
+
+  @Override
+  public native void setInt8(int byteOffset, int value) /*-{
+    this.setInt8(byteOffset, value);
+  }-*/;
+
+  @Override
+  public native void setUint16(int byteOffset, int value) /*-{
+    this.setUint16(byteOffset, value);
+  }-*/;
+
+  @Override
+  public native void setUint16(int byteOffset, int value, boolean littleEndian) /*-{
+    this.setUint16(byteOffset, value, littleEndian);
+  }-*/;
+
+  @Override
+  public void setUint32(int byteOffset, long value) {
+    setUint32FromDouble(byteOffset, value);
+  }
+
+  @Override
+  public void setUint32(int byteOffset, long value, boolean littleEndian) {
+    setUint32FromDouble(byteOffset, value, littleEndian);
+  }
+
+  @Override
+  public native void setUint32FromDouble(int byteOffset, double value) /*-{
+    this.setUint32(byteOffset, value);
+  }-*/;
+
+  @Override
+  public native void setUint32FromDouble(int byteOffset, double value, boolean littleEndian) /*-{
+    this.setUint32(byteOffset, value, littleEndian);
+  }-*/;
+
+  @Override
+  public native void setUint8(int byteOffset, int value) /*-{
+    this.setUint8(byteOffset, value);
+  }-*/;
+}
diff --git a/user/src/com/google/gwt/typedarrays/client/DataViewNativeEmul.java b/user/src/com/google/gwt/typedarrays/client/DataViewNativeEmul.java
new file mode 100644
index 0000000..ba2cd14
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/DataViewNativeEmul.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.DataView;
+import com.google.gwt.typedarrays.shared.Float32Array;
+import com.google.gwt.typedarrays.shared.Float64Array;
+import com.google.gwt.typedarrays.shared.Int16Array;
+import com.google.gwt.typedarrays.shared.Int32Array;
+import com.google.gwt.typedarrays.shared.Uint16Array;
+import com.google.gwt.typedarrays.shared.Uint32Array;
+
+/**
+ * JS native implementation of {@link DataView} for platforms with typed array
+ * support but missing DataView (ie, Firefox).
+ */
+public class DataViewNativeEmul implements DataView {
+
+  private static final boolean nativeLittleEndian;
+
+  static {
+    nativeLittleEndian = isNativeLittleEndian();
+  }
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param byteLength
+   * @return a {@link DataView} instance
+   */
+  public static DataView create(ArrayBuffer buffer, int byteOffset,
+      int byteLength) {
+    return new DataViewNativeEmul(buffer, byteOffset, byteLength);
+  }
+
+  /**
+   * @return true if this platform's typed arrays are little-endian
+   */
+  private static native boolean isNativeLittleEndian() /*-{
+    var i8 = new Int8Array(4);
+    i8[0] = 1;
+    i8[1] = 2;
+    i8[2] = 3;
+    i8[3] = 4;
+    var i32 = new Int32Array(i8.buffer);
+    // TODO(jat): do we need to check for other endianness beside BE/LE?
+    return i32[0] == 0x04030201;
+  }-*/;
+
+  protected final ArrayBuffer buffer;
+  protected final int bufferByteOffset;
+  protected final int byteLength;
+  
+  /**
+   * A temporary buffer used for reversing bytes.
+   */
+  protected final Uint8ArrayNative tempBuffer;
+
+  /**
+   * A view of the underlying buffer as bytes.
+   */
+  protected final Uint8ArrayNative uint8Array;
+
+  protected DataViewNativeEmul(ArrayBuffer buffer, int byteOffset, int byteLength) {
+    this.buffer = buffer;
+    this.bufferByteOffset = byteOffset;
+    this.byteLength = byteLength;
+    tempBuffer = Uint8ArrayNative.create(ArrayBufferNative.create(8), 0, 8);
+    uint8Array = Uint8ArrayNative.create(buffer, byteOffset, byteLength);
+  }
+
+  @Override
+  public ArrayBuffer buffer() {
+    return buffer;
+  }
+
+  @Override
+  public int byteLength() {
+    return byteLength;
+  }
+
+  @Override
+  public int byteOffset() {
+    return bufferByteOffset;
+  }
+
+  @Override
+  public float getFloat32(int byteOffset) {
+    return getFloat32(byteOffset, false);
+  }
+
+  @Override
+  public float getFloat32(int byteOffset, boolean littleEndian) {
+    ArrayBuffer buf = buffer;
+    int ofs = bufferByteOffset + byteOffset;
+    int len = Float32Array.BYTES_PER_ELEMENT;
+    if (littleEndian != nativeLittleEndian) {
+      reverseBytes(uint8Array, ofs, len, tempBuffer, 0);
+      buf = tempBuffer.buffer();
+      ofs = 0;
+    }
+    return Float32ArrayNative.create(buf, ofs, 1).get(0);
+  }
+
+  @Override
+  public double getFloat64(int byteOffset) {
+    return getFloat64(byteOffset, false);
+  }
+
+  @Override
+  public double getFloat64(int byteOffset, boolean littleEndian) {
+    ArrayBuffer buf = buffer;
+    int ofs = bufferByteOffset + byteOffset;
+    int len = Float64Array.BYTES_PER_ELEMENT;
+    if (littleEndian != nativeLittleEndian) {
+      reverseBytes(uint8Array, ofs, len, tempBuffer, 0);
+      buf = tempBuffer.buffer();
+      ofs = 0;
+    }
+    return Float64ArrayNative.create(buf, ofs, 1).get(0);
+  }
+
+  @Override
+  public short getInt16(int byteOffset) {
+    return getInt16(byteOffset, false);
+  }
+
+  @Override
+  public short getInt16(int byteOffset, boolean littleEndian) {
+    ArrayBuffer buf = buffer;
+    int ofs = bufferByteOffset + byteOffset;
+    int len = Int16Array.BYTES_PER_ELEMENT;
+    if (littleEndian != nativeLittleEndian) {
+      reverseBytes(uint8Array, ofs, len, tempBuffer, 0);
+      buf = tempBuffer.buffer();
+      ofs = 0;
+    }
+    return Int16ArrayNative.create(buf, ofs, 1).get(0);
+  }
+
+  @Override
+  public int getInt32(int byteOffset) {
+    return getInt32(byteOffset, false);
+  }
+
+  @Override
+  public int getInt32(int byteOffset, boolean littleEndian) {
+    ArrayBuffer buf = buffer;
+    int ofs = bufferByteOffset + byteOffset;
+    int len = Int32Array.BYTES_PER_ELEMENT;
+    if (littleEndian != nativeLittleEndian) {
+      reverseBytes(uint8Array, ofs, len, tempBuffer, 0);
+      buf = tempBuffer.buffer();
+      ofs = 0;
+    }
+    return Int32ArrayNative.create(buf, ofs, 1).get(0);
+  }
+
+  @Override
+  public byte getInt8(int byteOffset) {
+    return Int8ArrayNative.create(buffer, byteOffset, 1).get(0);
+  }
+
+  @Override
+  public int getUint16(int byteOffset) {
+    return getUint16(byteOffset, false);
+  }
+
+  @Override
+  public int getUint16(int byteOffset, boolean littleEndian) {
+    ArrayBuffer buf = buffer;
+    int ofs = bufferByteOffset + byteOffset;
+    int len = Uint16Array.BYTES_PER_ELEMENT;
+    if (littleEndian != nativeLittleEndian) {
+      reverseBytes(uint8Array, ofs, len, tempBuffer, 0);
+      buf = tempBuffer.buffer();
+      ofs = 0;
+    }
+    return Uint16ArrayNative.create(buf, ofs, 1).get(0);
+  }
+
+  @Override
+  public long getUint32(int byteOffset) {
+    return getUint32(byteOffset, false);
+  }
+
+  @Override
+  public long getUint32(int byteOffset, boolean littleEndian) {
+    ArrayBuffer buf = buffer;
+    int ofs = bufferByteOffset + byteOffset;
+    int len = Uint32Array.BYTES_PER_ELEMENT;
+    if (littleEndian != nativeLittleEndian) {
+      reverseBytes(uint8Array, ofs, len, tempBuffer, 0);
+      buf = tempBuffer.buffer();
+      ofs = 0;
+    }
+    return Uint32ArrayNative.create(buf, ofs, 1).get(0);
+  }
+
+  @Override
+  public double getUint32AsDouble(int byteOffset) {
+    return getUint32(byteOffset, false);
+  }
+
+  @Override
+  public double getUint32AsDouble(int byteOffset, boolean littleEndian) {
+    return getUint32(byteOffset, littleEndian);
+  }
+
+  @Override
+  public short getUint8(int byteOffset) {
+    return Uint8ArrayNative.create(buffer, byteOffset, 1).get(0);
+  }
+
+  @Override
+  public void setFloat32(int byteOffset, float value) {
+    setFloat32(byteOffset, value, false);
+  }
+
+  @Override
+  public void setFloat32(int byteOffset, float value, boolean littleEndian) {
+    ArrayBuffer buf = buffer;
+    int ofs = bufferByteOffset + byteOffset;
+    int finalOfs = ofs;
+    int len = Float32Array.BYTES_PER_ELEMENT;
+    if (littleEndian != nativeLittleEndian) {
+      buf = tempBuffer.buffer();
+      ofs = 0;
+    }
+    Float32ArrayNative.create(buf, ofs, 1).set(0, value);
+    if (littleEndian != nativeLittleEndian) {
+      reverseBytes(tempBuffer, 0, len, uint8Array, finalOfs);
+    }
+  }
+
+  @Override
+  public void setFloat64(int byteOffset, double value) {
+    setFloat64(byteOffset, value, false);
+  }
+
+  @Override
+  public void setFloat64(int byteOffset, double value, boolean littleEndian) {
+    ArrayBuffer buf = buffer;
+    int ofs = bufferByteOffset + byteOffset;
+    int finalOfs = ofs;
+    int len = Float64Array.BYTES_PER_ELEMENT;
+    if (littleEndian != nativeLittleEndian) {
+      buf = tempBuffer.buffer();
+      ofs = 0;
+    }
+    Float64ArrayNative.create(buf, ofs, 1).set(0, value);
+    if (littleEndian != nativeLittleEndian) {
+      reverseBytes(tempBuffer, 0, len, uint8Array, finalOfs);
+    }
+  }
+
+  @Override
+  public void setInt16(int byteOffset, int value) {
+    setInt16(byteOffset, value, false);
+  }
+
+  @Override
+  public void setInt16(int byteOffset, int value, boolean littleEndian) {
+    ArrayBuffer buf = buffer;
+    int ofs = bufferByteOffset + byteOffset;
+    int finalOfs = ofs;
+    int len = Int16Array.BYTES_PER_ELEMENT;
+    if (littleEndian != nativeLittleEndian) {
+      buf = tempBuffer.buffer();
+      ofs = 0;
+    }
+    Int16ArrayNative.create(buf, ofs, 1).set(0, value);
+    if (littleEndian != nativeLittleEndian) {
+      reverseBytes(tempBuffer, 0, len, uint8Array, finalOfs);
+    }
+  }
+
+  @Override
+  public void setInt32(int byteOffset, int value) {
+    setInt32(byteOffset, value, false);
+  }
+
+  @Override
+  public void setInt32(int byteOffset, int value, boolean littleEndian) {
+    ArrayBuffer buf = buffer;
+    int ofs = bufferByteOffset + byteOffset;
+    int finalOfs = ofs;
+    int len = Int32Array.BYTES_PER_ELEMENT;
+    if (littleEndian != nativeLittleEndian) {
+      buf = tempBuffer.buffer();
+      ofs = 0;
+    }
+    Int32ArrayNative.create(buf, ofs, 1).set(0, value);
+    if (littleEndian != nativeLittleEndian) {
+      reverseBytes(tempBuffer, 0, len, uint8Array, finalOfs);
+    }
+  }
+
+  @Override
+  public void setInt8(int byteOffset, int value) {
+    Int8ArrayNative.create(buffer, byteOffset, 1).set(0, value);
+  }
+
+  @Override
+  public void setUint16(int byteOffset, int value) {
+    setUint16(byteOffset, value, false);
+  }
+
+  @Override
+  public void setUint16(int byteOffset, int value, boolean littleEndian) {
+    ArrayBuffer buf = buffer;
+    int ofs = bufferByteOffset + byteOffset;
+    int finalOfs = ofs;
+    int len = Uint16Array.BYTES_PER_ELEMENT;
+    if (littleEndian != nativeLittleEndian) {
+      buf = tempBuffer.buffer();
+      ofs = 0;
+    }
+    Uint16ArrayNative.create(buf, ofs, 1).set(0, value);
+    if (littleEndian != nativeLittleEndian) {
+      reverseBytes(tempBuffer, 0, len, uint8Array, finalOfs);
+    }
+  }
+
+  @Override
+  public void setUint32(int byteOffset, long value) {
+    setUint32(byteOffset, value, false);
+  }
+
+  @Override
+  public void setUint32(int byteOffset, long value, boolean littleEndian) {
+    ArrayBuffer buf = buffer;
+    int ofs = bufferByteOffset + byteOffset;
+    int finalOfs = ofs;
+    int len = Uint32Array.BYTES_PER_ELEMENT;
+    if (littleEndian != nativeLittleEndian) {
+      buf = tempBuffer.buffer();
+      ofs = 0;
+    }
+    Uint32ArrayNative.create(buf, ofs, 1).set(0, value);
+    if (littleEndian != nativeLittleEndian) {
+      reverseBytes(tempBuffer, 0, len, uint8Array, finalOfs);
+    }
+  }
+
+  @Override
+  public void setUint32FromDouble(int byteOffset, double value) {
+    setUint32FromDouble(byteOffset, value, false);
+  }
+
+  @Override
+  public void setUint32FromDouble(int byteOffset, double value, boolean littleEndian) {
+    ArrayBuffer buf = buffer;
+    int ofs = bufferByteOffset + byteOffset;
+    int finalOfs = ofs;
+    int len = Uint32Array.BYTES_PER_ELEMENT;
+    if (littleEndian != nativeLittleEndian) {
+      buf = tempBuffer.buffer();
+      ofs = 0;
+    }
+    Uint32ArrayNative.create(buf, ofs, 1).set(0, value);
+    if (littleEndian != nativeLittleEndian) {
+      reverseBytes(tempBuffer, 0, len, uint8Array, finalOfs);
+    }
+  }
+
+  @Override
+  public void setUint8(int byteOffset, int value) {
+    Uint8ArrayNative.create(buffer, byteOffset, 1).set(0, value);
+  }
+
+  /**
+   * Copy bytes from the underlying buffer to a temporary buffer, reversing them
+   * in the process.
+   * 
+   * @param src
+   * @param srcOfs offset into {@code buffer}
+   * @param len number of bytes to copy
+   * @param dest
+   * @param destOfs
+   */
+  protected final void reverseBytes(Uint8ArrayNative src, int srcOfs, int len,
+      Uint8ArrayNative dest, int destOfs) {
+    for (int i = 0; i < len; ++i) {
+      dest.set(i + destOfs, src.get(srcOfs + len - 1 - i));
+    }
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/client/Float32ArrayNative.java b/user/src/com/google/gwt/typedarrays/client/Float32ArrayNative.java
new file mode 100644
index 0000000..e63e070
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/Float32ArrayNative.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayUtils;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Float32Array;
+
+/**
+ * JS native implementation of {@link Float32Array}.
+ */
+public final class Float32ArrayNative extends ArrayBufferViewNative implements Float32Array {
+
+  /**
+   * @param buffer
+   * @return a {@link Float32Array} instance
+   */
+  public static native Float32ArrayNative create(ArrayBuffer buffer) /*-{
+    return new Float32Array(buffer);
+  }-*/;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @return a {@link Float32Array} instance
+   */
+  public static native Float32ArrayNative create(ArrayBuffer buffer, int byteOffset) /*-{
+    return new Float32Array(buffer, byteOffset);
+  }-*/;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   * @return a {@link Float32Array} instance
+   */
+  public static native Float32ArrayNative create(ArrayBuffer buffer, int byteOffset,
+      int length) /*-{
+    return new Float32Array(buffer, byteOffset, length);
+  }-*/;
+
+  /**
+   * @param length
+   * @return a {@link Float32Array} instance
+   */
+  public static native Float32ArrayNative create(int length) /*-{
+    return new Float32Array(length);
+  }-*/;
+
+  protected Float32ArrayNative() {
+  }
+
+  @Override
+  public native float get(int index) /*-{
+    return this[index];
+  }-*/;
+
+  @Override
+  public native int length() /*-{
+    return this.length;
+  }-*/;
+
+  @Override
+  public void set(float[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(float[] array, int offset) {
+    set(JsArrayUtils.readOnlyJsArray(array), offset);
+  }
+
+  @Override
+  public native void set(Float32Array array) /*-{
+    this.set(array);
+  }-*/;
+
+  @Override
+  public native void set(Float32Array array, int offset) /*-{
+    this.set(array, offset);
+  }-*/;
+
+  @Override
+  public native void set(int index, float value) /*-{
+    this[index] = value;
+  }-*/;
+
+  @Override
+  public native Float32Array subarray(int begin) /*-{
+    return this.subarray(begin);
+  }-*/;
+
+  @Override
+  public native Float32Array subarray(int begin, int end) /*-{
+    return this.subarray(begin, end);
+  }-*/;
+
+  private native void set(JavaScriptObject array, int offset) /*-{
+    this.set(array, offset);
+  }-*/;
+}
diff --git a/user/src/com/google/gwt/typedarrays/client/Float64ArrayNative.java b/user/src/com/google/gwt/typedarrays/client/Float64ArrayNative.java
new file mode 100644
index 0000000..2405c3f
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/Float64ArrayNative.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayUtils;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Float64Array;
+
+/**
+ * JS native implementation of {@link Float64Array}.
+ */
+public final class Float64ArrayNative extends ArrayBufferViewNative implements Float64Array {
+
+  /**
+   * @param buffer
+   * @return a {@link Float64Array} instance
+   */
+  public static native Float64ArrayNative create(ArrayBuffer buffer) /*-{
+    return new Float64Array(buffer);
+  }-*/;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @return a {@link Float64Array} instance
+   */
+  public static native Float64ArrayNative create(ArrayBuffer buffer, int byteOffset) /*-{
+    return new Float64Array(buffer, byteOffset);
+  }-*/;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   * @return a {@link Float64Array} instance
+   */
+  public static native Float64ArrayNative create(ArrayBuffer buffer, int byteOffset,
+      int length) /*-{
+    return new Float64Array(buffer, byteOffset, length);
+  }-*/;
+
+  /**
+   * @param length
+   * @return a {@link Float64Array} instance
+   */
+  public static native Float64ArrayNative create(int length) /*-{
+    return new Float64Array(length);
+  }-*/;
+
+  protected Float64ArrayNative() {
+  }
+
+  @Override
+  public native double get(int index) /*-{
+    return this[index];
+  }-*/;
+
+  @Override
+  public native int length() /*-{
+    return this.length;
+  }-*/;
+
+  @Override
+  public void set(double[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(double[] array, int offset) {
+    set(JsArrayUtils.readOnlyJsArray(array), offset);
+  }
+
+  @Override
+  public native void set(Float64Array array) /*-{
+    this.set(array);
+  }-*/;
+
+  @Override
+  public native void set(Float64Array array, int offset) /*-{
+    this.set(array, offset);
+  }-*/;
+
+  @Override
+  public native void set(int index, double value) /*-{
+    this[index] = value;
+  }-*/;
+
+  @Override
+  public native Float64Array subarray(int begin) /*-{
+    return this.subarray(begin);
+  }-*/;
+
+  @Override
+  public native Float64Array subarray(int begin, int end) /*-{
+    return this.subarray(begin, end);
+  }-*/;
+
+  private native void set(JavaScriptObject array, int offset) /*-{
+    this.set(array, offset);
+  }-*/;
+}
diff --git a/user/src/com/google/gwt/typedarrays/client/Int16ArrayNative.java b/user/src/com/google/gwt/typedarrays/client/Int16ArrayNative.java
new file mode 100644
index 0000000..b3331f0
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/Int16ArrayNative.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayUtils;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Int16Array;
+
+/**
+ * JS native implementation of {@link Int16Array}.
+ */
+public final class Int16ArrayNative extends ArrayBufferViewNative implements Int16Array {
+
+  /**
+   * @param buffer
+   * @return a {@link Int16Array} instance
+   */
+  public static native Int16ArrayNative create(ArrayBuffer buffer) /*-{
+    return new Int16Array(buffer);
+  }-*/;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @return a {@link Int16Array} instance
+   */
+  public static native Int16ArrayNative create(ArrayBuffer buffer, int byteOffset) /*-{
+    return new Int16Array(buffer, byteOffset);
+  }-*/;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   * @return a {@link Int16Array} instance
+   */
+  public static native Int16ArrayNative create(ArrayBuffer buffer, int byteOffset,
+      int length) /*-{
+    return new Int16Array(buffer, byteOffset, length);
+  }-*/;
+
+  /**
+   * @param length
+   * @return a {@link Int16Array} instance
+   */
+  public static native Int16ArrayNative create(int length) /*-{
+    return new Int16Array(length);
+  }-*/;
+
+  protected Int16ArrayNative() {
+  }
+
+  @Override
+  public native short get(int index) /*-{
+    return this[index];
+  }-*/;
+
+  @Override
+  public native int length() /*-{
+    return this.length;
+  }-*/;
+
+  @Override
+  public native void set(int index, int value) /*-{
+    this[index] = value;
+  }-*/;
+
+  @Override
+  public void set(int[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(int[] array, int offset) {
+    set(JsArrayUtils.readOnlyJsArray(array), offset);
+  }
+
+  @Override
+  public native void set(Int16Array array) /*-{
+    this.set(array);
+  }-*/;
+
+  @Override
+  public native void set(Int16Array array, int offset) /*-{
+    this.set(array, offset);
+  }-*/;
+
+  @Override
+  public void set(short[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(short[] array, int offset) {
+    set(JsArrayUtils.readOnlyJsArray(array), offset);
+  }
+
+  @Override
+  public native Int16Array subarray(int begin) /*-{
+    return this.subarray(begin);
+  }-*/;
+
+  @Override
+  public native Int16Array subarray(int begin, int end) /*-{
+    return this.subarray(begin, end);
+  }-*/;
+
+  private native void set(JavaScriptObject array, int offset) /*-{
+    this.set(array, offset);
+  }-*/;
+}
diff --git a/user/src/com/google/gwt/typedarrays/client/Int32ArrayNative.java b/user/src/com/google/gwt/typedarrays/client/Int32ArrayNative.java
new file mode 100644
index 0000000..f6ace6c
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/Int32ArrayNative.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayUtils;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Int32Array;
+
+/**
+ * JS native implementation of {@link Int32Array}.
+ */
+public final class Int32ArrayNative extends ArrayBufferViewNative implements Int32Array {
+
+  /**
+   * @param buffer
+   * @return a {@link Int32Array} instance
+   */
+  public static native Int32ArrayNative create(ArrayBuffer buffer) /*-{
+    return new Int32Array(buffer);
+  }-*/;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @return a {@link Int32Array} instance
+   */
+  public static native Int32ArrayNative create(ArrayBuffer buffer, int byteOffset) /*-{
+    return new Int32Array(buffer, byteOffset);
+  }-*/;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   * @return a {@link Int32Array} instance
+   */
+  public static native Int32ArrayNative create(ArrayBuffer buffer, int byteOffset, int length) /*-{
+    return new Int32Array(buffer, byteOffset, length);
+  }-*/;
+
+  /**
+   * @param length
+   * @return a {@link Int32Array} instance
+   */
+  public static native Int32ArrayNative create(int length) /*-{
+    return new Int32Array(length);
+  }-*/;
+
+  protected Int32ArrayNative() {
+  }
+
+  @Override
+  public native int get(int index) /*-{
+    return this[index];
+  }-*/;
+
+  @Override
+  public native int length() /*-{
+    return this.length;
+  }-*/;
+
+  @Override
+  public native void set(int index, int value) /*-{
+    this[index] = value;
+  }-*/;
+
+  @Override
+  public void set(int[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(int[] array, int offset) {
+    set(JsArrayUtils.readOnlyJsArray(array), offset);
+  }
+
+  @Override
+  public native void set(Int32Array array) /*-{
+    this.set(array);
+  }-*/;
+
+  @Override
+  public native void set(Int32Array array, int offset) /*-{
+    this.set(array, offset);
+  }-*/;
+
+  @Override
+  public native Int32Array subarray(int begin) /*-{
+    return this.subarray(begin);
+  }-*/;
+
+  @Override
+  public native Int32Array subarray(int begin, int end) /*-{
+    return this.subarray(begin, end);
+  }-*/;
+
+  private native void set(JavaScriptObject array, int offset) /*-{
+    this.set(array, offset);
+  }-*/;
+}
diff --git a/user/src/com/google/gwt/typedarrays/client/Int8ArrayNative.java b/user/src/com/google/gwt/typedarrays/client/Int8ArrayNative.java
new file mode 100644
index 0000000..9e32ed9
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/Int8ArrayNative.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayUtils;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Int8Array;
+
+/**
+ * JS native implementation of {@link Int8Array}.
+ */
+public final class Int8ArrayNative extends ArrayBufferViewNative implements Int8Array {
+
+  /**
+   * @param buffer
+   * @return a {@link Int8Array} instance
+   */
+  public static native Int8ArrayNative create(ArrayBuffer buffer) /*-{
+    return new Int8Array(buffer);
+  }-*/;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @return a {@link Int8Array} instance
+   */
+  public static native Int8ArrayNative create(ArrayBuffer buffer, int byteOffset) /*-{
+    return new Int8Array(buffer, byteOffset);
+  }-*/;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   * @return a {@link Int8Array} instance
+   */
+  public static native Int8ArrayNative create(ArrayBuffer buffer, int byteOffset,
+      int length) /*-{
+    return new Int8Array(buffer, byteOffset, length);
+  }-*/;
+
+  /**
+   * @param length
+   * @return a {@link Int8Array} instance
+   */
+  public static native Int8ArrayNative create(int length) /*-{
+    return new Int8Array(length);
+  }-*/;
+
+  protected Int8ArrayNative() {
+  }
+
+  @Override
+  public native byte get(int index) /*-{
+    return this[index];
+  }-*/;
+
+  @Override
+  public native int length() /*-{
+    return this.length;
+  }-*/;
+
+  @Override
+  public void set(byte[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(byte[] array, int offset) {
+    set(JsArrayUtils.readOnlyJsArray(array), offset);
+  }
+
+  @Override
+  public native void set(int index, int value) /*-{
+    this[index] = value;
+  }-*/;
+
+  @Override
+  public void set(int[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(int[] array, int offset) {
+    set(JsArrayUtils.readOnlyJsArray(array), offset);
+  }
+
+  @Override
+  public native void set(Int8Array array) /*-{
+    this.set(array);
+  }-*/;
+
+  @Override
+  public native void set(Int8Array array, int offset) /*-{
+    this.set(array, offset);
+  }-*/;
+
+  @Override
+  public native Int8Array subarray(int begin) /*-{
+    return this.subarray(begin);
+  }-*/;
+
+  @Override
+  public native Int8Array subarray(int begin, int end) /*-{
+    return this.subarray(begin, end);
+  }-*/;
+
+  private native void set(JavaScriptObject array, int offset) /*-{
+    this.set(array, offset);
+  }-*/;
+}
diff --git a/user/src/com/google/gwt/typedarrays/client/JsUtils.java b/user/src/com/google/gwt/typedarrays/client/JsUtils.java
new file mode 100644
index 0000000..0289944
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/JsUtils.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JsArrayInteger;
+import com.google.gwt.core.client.JsArrayNumber;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Float32Array;
+import com.google.gwt.typedarrays.shared.Float64Array;
+import com.google.gwt.typedarrays.shared.Int16Array;
+import com.google.gwt.typedarrays.shared.Int32Array;
+import com.google.gwt.typedarrays.shared.Int8Array;
+import com.google.gwt.typedarrays.shared.Uint16Array;
+import com.google.gwt.typedarrays.shared.Uint32Array;
+import com.google.gwt.typedarrays.shared.Uint8Array;
+import com.google.gwt.typedarrays.shared.Uint8ClampedArray;
+
+/**
+ * JS-specific utility methods, for use in client-side code that has the values in
+ * JS objects already.
+ */
+public class JsUtils {
+
+  /**
+   * Creates an {@link ArrayBuffer} from a string, with bytes encoded as
+   * individual characters (which means in UTF8-encoded strings, byte
+   * values {@code 0x80-0xFF} take two bytes. 
+   * 
+   * @param str
+   * @return an {@link ArrayBuffer} containing the bytes decoded from the
+   *     string
+   */
+  public static native ArrayBuffer arrayBufferFromString(String str) /*-{
+    // TODO(jat): more efficient way to do this?
+    var len = str.length;
+    var buf = new Uint8Array(len);
+    for (var i = 0; i < len; ++i) {
+       buf[i] = str.charCodeAt(i);
+    }
+    return buf.buffer;
+  }-*/;
+
+  public static native Float32ArrayNative createFloat32Array(JsArrayNumber array) /*-{
+    return new Float32Array(array);
+  }-*/;
+
+  public static native Float64ArrayNative createFloat64Array(JsArrayNumber array) /*-{
+    return new Float64Array(array);
+  }-*/;
+
+  public static native Int16ArrayNative createInt16Array(JsArrayInteger array) /*-{
+    return new Int16Array(array);
+  }-*/;
+
+  public static native Int32ArrayNative createInt32Array(JsArrayInteger array) /*-{
+    return new Int32Array(array);
+  }-*/;
+
+  public static native Int8ArrayNative createInt8Array(JsArrayInteger array) /*-{
+    return new Int8Array(array);
+  }-*/;
+
+  public static native Uint16ArrayNative createUint16Array(JsArrayInteger array) /*-{
+    return new Uint16Array(array);
+  }-*/;
+
+  public static native Uint32ArrayNative createUint32Array(JsArrayNumber array) /*-{
+    return new Uint32Array(array);
+  }-*/;
+
+  public static native Uint8ArrayNative createUint8Array(JsArrayInteger array) /*-{
+    return new Uint8Array(array);
+  }-*/;
+
+  public static Uint8ClampedArray createUint8ClampedArray(JsArrayInteger array) {
+    if (hasClampedArray()) {
+      return Uint8ArrayNative.createClamped(array);
+    } else {
+      return Uint8ClampedArrayNativeEmul.create(array);
+    }
+  }
+
+  public static native void set(Float32Array dest, JsArrayNumber array) /*-{
+    dest.set(array);
+  }-*/;
+
+  public static native void set(Float32Array dest, JsArrayNumber array, int offset) /*-{
+    dest.set(array, offset);
+  }-*/;
+
+  public static native void set(Float64Array dest, JsArrayNumber array) /*-{
+    dest.set(array);
+  }-*/;
+
+  public static native void set(Float64Array dest, JsArrayNumber array, int offset) /*-{
+    dest.set(array, offset);
+  }-*/;
+
+  public static native void set(Int16Array dest, JsArrayInteger array) /*-{
+    dest.set(array);
+  }-*/;
+
+  public static native void set(Int16Array dest, JsArrayInteger array, int offset) /*-{
+    dest.set(array, offset);
+  }-*/;
+
+  public static native void set(Int32Array dest, JsArrayInteger array) /*-{
+    dest.set(array);
+  }-*/;
+
+  public static native void set(Int32Array dest, JsArrayInteger array, int offset) /*-{
+    dest.set(array, offset);
+  }-*/;
+
+  public static native void set(Int8Array dest, JsArrayInteger array) /*-{
+    dest.set(array);
+  }-*/;
+
+  public static native void set(Int8Array dest, JsArrayInteger array, int offset) /*-{
+    dest.set(array, offset);
+  }-*/;
+
+  public static native void set(Uint16Array dest, JsArrayInteger array) /*-{
+    dest.set(array);
+  }-*/;
+
+  public static native void set(Uint16Array dest, JsArrayInteger array, int offset) /*-{
+    dest.set(array, offset);
+  }-*/;
+
+  public static native void set(Uint32Array dest, JsArrayNumber array) /*-{
+    dest.set(array);
+  }-*/;
+
+  public static native void set(Uint32Array dest, JsArrayNumber array, int offset) /*-{
+    dest.set(array, offset);
+  }-*/;
+
+  public static native void set(Uint8Array dest, JsArrayInteger array) /*-{
+    dest.set(array);
+  }-*/;
+
+  public static native void set(Uint8Array dest, JsArrayInteger array, int offset) /*-{
+    dest.set(array, offset);
+  }-*/;
+
+  public static void set(Uint8ClampedArray dest, JsArrayInteger array) {
+    if (hasClampedArray()) {
+      set((Uint8Array) dest, array, 0);
+    } else {
+      int len = array.length();
+      for (int i = 0; i < len; ++i) {
+        dest.set(i, array.get(i));
+      }
+    }
+  }
+
+  public static void set(Uint8ClampedArray dest, JsArrayInteger array, int offset) {
+    if (hasClampedArray()) {
+      set((Uint8Array) dest, array, offset);
+    } else {
+      int len = array.length();
+      for (int i = 0; i < len; ++i) {
+        dest.set(i + offset, array.get(i));
+      }
+    }
+  }
+
+  /**
+   * Creates a string from an {@link ArrayBuffer}, with bytes encoded as
+   * individual characters (which means in UTF8-encoded strings, byte
+   * values {@code 0x80-0xFF} take two bytes. 
+   * 
+   * @param buf
+   * @return a string encoding the bytes in the {@link ArrayBuffer}
+   */
+  public static native String stringFromArrayBuffer(ArrayBuffer buf) /*-{
+    // TODO(jat): more efficient way to do this?
+    var cc = [];
+    var i8 = new Uint8Array(buf);
+    for (var i = 0; i < buf.byteLength; ++i) {
+      cc.push(i8[i]);
+    }
+    return String.fromCharCode.apply(null, cc);
+  }-*/;
+
+  private static native boolean hasClampedArray() /*-{
+    // TODO(jat): this is awkward - should this be deferred bound?
+    return !!(window.Uint8ClampedArray);
+  }-*/;
+
+  private JsUtils() {
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/client/NativeImpl.java b/user/src/com/google/gwt/typedarrays/client/NativeImpl.java
new file mode 100644
index 0000000..5f1bda7
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/NativeImpl.java
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JsArrayUtils;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.DataView;
+import com.google.gwt.typedarrays.shared.TypedArrays.Impl;
+import com.google.gwt.typedarrays.shared.Uint8ClampedArray;
+
+/**
+ * The default implementation class, which assumes that Typed Arrays might be
+ * supported and does runtime checks where necessary, substituting emulated
+ * implementations of DataView and Uint8ClampedArray where they are missing.
+ * <p>
+ * This can be replaced with a version which avoids runtime checks where
+ * possible for efficiency.
+ */
+public class NativeImpl extends Impl {
+
+  @Override
+  public ArrayBuffer createArrayBuffer(int length) {
+    return ArrayBufferNative.create(length);
+  }
+
+  @Override
+  public DataView createDataView(ArrayBuffer buffer) {
+    if (checkDataViewSupport()) {
+      return DataViewNative.create(buffer);
+    } else {
+      return DataViewNativeEmul.create(buffer, 0, buffer.byteLength());
+    }
+  }
+
+  @Override
+  public DataView createDataView(ArrayBuffer buffer, int byteOffset) {
+    if (checkDataViewSupport()) {
+      return DataViewNative.create(buffer, byteOffset);
+    } else {
+      return DataViewNativeEmul.create(buffer, byteOffset, buffer.byteLength() - byteOffset);
+    }
+  }
+
+  @Override
+  public DataView createDataView(ArrayBuffer buffer, int byteOffset,
+      int byteLength) {
+    if (checkDataViewSupport()) {
+      return DataViewNative.create(buffer, byteOffset, byteLength);
+    } else {
+      return DataViewNativeEmul.create(buffer, byteOffset, byteLength);
+    }
+  }
+
+  @Override
+  public Float32ArrayNative createFloat32Array(ArrayBuffer buffer) {
+    return Float32ArrayNative.create(buffer);
+  }
+
+  @Override
+  public Float32ArrayNative createFloat32Array(ArrayBuffer buffer, int byteOffset) {
+    return Float32ArrayNative.create(buffer, byteOffset);
+  }
+
+  @Override
+  public Float32ArrayNative createFloat32Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return Float32ArrayNative.create(buffer, byteOffset, length);
+  }
+
+  @Override
+  public Float32ArrayNative createFloat32Array(float[] array) {
+    return JsUtils.createFloat32Array(JsArrayUtils.readOnlyJsArray(array));
+  }
+
+  @Override
+  public Float32ArrayNative createFloat32Array(int length) {
+    return Float32ArrayNative.create(length);
+  }
+
+  @Override
+  public Float64ArrayNative createFloat64Array(ArrayBuffer buffer) {
+    return Float64ArrayNative.create(buffer);
+  }
+
+  @Override
+  public Float64ArrayNative createFloat64Array(ArrayBuffer buffer, int byteOffset) {
+    return Float64ArrayNative.create(buffer, byteOffset);
+  }
+
+  @Override
+  public Float64ArrayNative createFloat64Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return Float64ArrayNative.create(buffer, byteOffset, length);
+  }
+
+  @Override
+  public Float64ArrayNative createFloat64Array(double[] array) {
+    return JsUtils.createFloat64Array(JsArrayUtils.readOnlyJsArray(array));
+  }
+
+  @Override
+  public Float64ArrayNative createFloat64Array(int length) {
+    return Float64ArrayNative.create(length);
+  }
+
+  @Override
+  public Int16ArrayNative createInt16Array(ArrayBuffer buffer) {
+    return Int16ArrayNative.create(buffer);
+  }
+
+  @Override
+  public Int16ArrayNative createInt16Array(ArrayBuffer buffer, int byteOffset) {
+    return Int16ArrayNative.create(buffer, byteOffset);
+  }
+
+  @Override
+  public Int16ArrayNative createInt16Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return Int16ArrayNative.create(buffer, byteOffset, length);
+  }
+
+  @Override
+  public Int16ArrayNative createInt16Array(int length) {
+    return Int16ArrayNative.create(length);
+  }
+
+  @Override
+  public Int16ArrayNative createInt16Array(short[] array) {
+    return JsUtils.createInt16Array(JsArrayUtils.readOnlyJsArray(array));
+  }
+
+  @Override
+  public Int32ArrayNative createInt32Array(ArrayBuffer buffer) {
+    return Int32ArrayNative.create(buffer);
+  }
+
+  @Override
+  public Int32ArrayNative createInt32Array(ArrayBuffer buffer, int byteOffset) {
+    return Int32ArrayNative.create(buffer, byteOffset);
+  }
+
+  @Override
+  public Int32ArrayNative createInt32Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return Int32ArrayNative.create(buffer, byteOffset, length);
+  }
+
+  @Override
+  public Int32ArrayNative createInt32Array(int length) {
+    return Int32ArrayNative.create(length);
+  }
+
+  @Override
+  public Int32ArrayNative createInt32Array(int[] array) {
+    return JsUtils.createInt32Array(JsArrayUtils.readOnlyJsArray(array));
+  }
+
+  @Override
+  public Int8ArrayNative createInt8Array(ArrayBuffer buffer) {
+    return Int8ArrayNative.create(buffer);
+  }
+
+  @Override
+  public Int8ArrayNative createInt8Array(ArrayBuffer buffer, int byteOffset) {
+    return Int8ArrayNative.create(buffer, byteOffset);
+  }
+
+  @Override
+  public Int8ArrayNative createInt8Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return Int8ArrayNative.create(buffer, byteOffset, length);
+  }
+
+  @Override
+  public Int8ArrayNative createInt8Array(byte[] array) {
+    return JsUtils.createInt8Array(JsArrayUtils.readOnlyJsArray(array));
+  }
+
+  @Override
+  public Int8ArrayNative createInt8Array(int length) {
+    return Int8ArrayNative.create(length);
+  }
+
+  @Override
+  public Uint16ArrayNative createUint16Array(ArrayBuffer buffer) {
+    return Uint16ArrayNative.create(buffer);
+  }
+
+  @Override
+  public Uint16ArrayNative createUint16Array(ArrayBuffer buffer, int byteOffset) {
+    return Uint16ArrayNative.create(buffer, byteOffset);
+  }
+
+  @Override
+  public Uint16ArrayNative createUint16Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return Uint16ArrayNative.create(buffer, byteOffset, length);
+  }
+
+  @Override
+  public Uint16ArrayNative createUint16Array(int length) {
+    return Uint16ArrayNative.create(length);
+  }
+
+  @Override
+  public Uint16ArrayNative createUint16Array(int[] array) {
+    return JsUtils.createUint16Array(JsArrayUtils.readOnlyJsArray(array));
+  }
+
+  @Override
+  public Uint32ArrayNative createUint32Array(ArrayBuffer buffer) {
+    return Uint32ArrayNative.create(buffer);
+  }
+
+  @Override
+  public Uint32ArrayNative createUint32Array(ArrayBuffer buffer, int byteOffset) {
+    return Uint32ArrayNative.create(buffer, byteOffset);
+  }
+
+  @Override
+  public Uint32ArrayNative createUint32Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return Uint32ArrayNative.create(buffer, byteOffset, length);
+  }
+
+  @Override
+  public Uint32ArrayNative createUint32Array(double[] array) {
+    return JsUtils.createUint32Array(JsArrayUtils.readOnlyJsArray(array));
+  }
+
+  @Override
+  public Uint32ArrayNative createUint32Array(int length) {
+    return Uint32ArrayNative.create(length);
+  }
+
+  @Override
+  public Uint32ArrayNative createUint32Array(long[] array) {
+    int len = array.length;
+    double[] temp = new double[len];
+    for (int i = 0; i < len; ++i) {
+      temp[i] = array[i];
+    }
+    return JsUtils.createUint32Array(JsArrayUtils.readOnlyJsArray(temp));
+  }
+
+  @Override
+  public Uint8ArrayNative createUint8Array(ArrayBuffer buffer) {
+    return Uint8ArrayNative.create(buffer);
+  }
+
+  @Override
+  public Uint8ArrayNative createUint8Array(ArrayBuffer buffer, int byteOffset) {
+    return Uint8ArrayNative.create(buffer, byteOffset);
+  }
+
+  @Override
+  public Uint8ArrayNative createUint8Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return Uint8ArrayNative.create(buffer, byteOffset, length);
+  }
+
+  @Override
+  public Uint8ArrayNative createUint8Array(int length) {
+    return Uint8ArrayNative.create(length);
+  }
+
+  @Override
+  public Uint8ArrayNative createUint8Array(short[] array) {
+    return JsUtils.createUint8Array(JsArrayUtils.readOnlyJsArray(array));
+  }
+
+  @Override
+  public Uint8ClampedArray createUint8ClampedArray(ArrayBuffer buffer) {
+    if (checkUint8ClampedArraySupport()) {
+      return Uint8ArrayNative.createClamped(buffer);
+    } else {
+      return Uint8ClampedArrayNativeEmul.create(buffer, 0, buffer.byteLength());
+    }
+  }
+
+  @Override
+  public Uint8ClampedArray createUint8ClampedArray(ArrayBuffer buffer, int byteOffset) {
+    if (checkUint8ClampedArraySupport()) {
+      return Uint8ArrayNative.createClamped(buffer, byteOffset);
+    } else {
+      return Uint8ClampedArrayNativeEmul.create(buffer, byteOffset,
+          buffer.byteLength() - byteOffset);
+    }
+  }
+
+  @Override
+  public Uint8ClampedArray createUint8ClampedArray(ArrayBuffer buffer,
+      int byteOffset, int length) {
+    if (checkUint8ClampedArraySupport()) {
+      return Uint8ArrayNative.createClamped(buffer, byteOffset, length);
+    } else {
+      return Uint8ClampedArrayNativeEmul.create(buffer, byteOffset, length);
+    }
+  }
+
+  @Override
+  public Uint8ClampedArray createUint8ClampedArray(int length) {
+    if (checkUint8ClampedArraySupport()) {
+      return Uint8ArrayNative.createClamped(length);
+    } else {
+      return Uint8ClampedArrayNativeEmul.create(createArrayBuffer(length), 0, length);
+    }
+  }
+
+  @Override
+  public Uint8ClampedArray createUint8ClampedArray(short[] array) {
+    if (checkUint8ClampedArraySupport()) {
+      return Uint8ArrayNative.createClamped(array);
+    } else {
+      return Uint8ClampedArrayNativeEmul.create(array);
+    }
+  }
+
+  protected native boolean checkDataViewSupport() /*-{
+    return !!(window.DataView);
+  }-*/;
+
+  protected native boolean checkUint8ClampedArraySupport() /*-{
+    return !!(window.Uint8ClampedArray);
+  }-*/;
+
+  @Override
+  protected native boolean runtimeSupportCheck() /*-{
+      return !!(window.ArrayBuffer);
+  }-*/;
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/typedarrays/client/NativeImplEmulClamped.java b/user/src/com/google/gwt/typedarrays/client/NativeImplEmulClamped.java
new file mode 100644
index 0000000..efd0d7b
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/NativeImplEmulClamped.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+/**
+ * An implementation class used for browsers which provide native
+ * implementations of {@link com.google.gwt.typedarrays.shared.DataView} but not
+ * {@link com.google.gwt.typedarrays.shared.Uint8ClampedArray}.
+ * <p>
+ * Current versions of WebKit and Opera are such browsers.
+ */
+public class NativeImplEmulClamped extends NativeImpl {
+  // TODO: can we override runtimeSupportCheck to return true?
+  // Chrome 7+, Safari 5.1+, iOS 4.2+, Android 4.0+, Opera 11.6+ support typed
+  // arrays.
+
+  @Override
+  protected boolean checkDataViewSupport() {
+    return true;
+  }
+
+  @Override
+  protected boolean checkUint8ClampedArraySupport() {
+    return false;
+  }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/typedarrays/client/NativeImplEmulDataView.java b/user/src/com/google/gwt/typedarrays/client/NativeImplEmulDataView.java
new file mode 100644
index 0000000..d0c0280
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/NativeImplEmulDataView.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+/**
+ * An implementation class used for browsers which provide native
+ * implementations of
+ * {@link com.google.gwt.typedarrays.shared.Uint8ClampedArray} but not
+ * {@link com.google.gwt.typedarrays.shared.DataView}.
+ * <p>
+ * Current versions of FireFox are such browsers.
+ */
+public class NativeImplEmulDataView extends NativeImpl {
+  // TODO: can we override runtimeSupportCheck to return true?
+  // FF4+ supports typed arrays (except DataView).
+
+  @Override
+  protected boolean checkDataViewSupport() {
+    return false;
+  }
+
+  @Override
+  protected boolean checkUint8ClampedArraySupport() {
+    return true;
+  }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/typedarrays/client/NativeImplFull.java b/user/src/com/google/gwt/typedarrays/client/NativeImplFull.java
new file mode 100644
index 0000000..eb82f24
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/NativeImplFull.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+/**
+ * An implementation class used for browsers which provide full native
+ * implementations of all typed array classes.
+ * <p>
+ * Current versions of Opera are such browsers.
+ */
+public class NativeImplFull extends NativeImpl {
+  // Opera 11.6+ (but not mini/mobile) supports typed arrays.
+
+  @Override
+  protected boolean checkDataViewSupport() {
+    return true;
+  }
+
+  @Override
+  protected boolean checkUint8ClampedArraySupport() {
+    return true;
+  }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/typedarrays/client/NoSupportImpl.java b/user/src/com/google/gwt/typedarrays/client/NoSupportImpl.java
new file mode 100644
index 0000000..d626456
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/NoSupportImpl.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.DataView;
+import com.google.gwt.typedarrays.shared.Float32Array;
+import com.google.gwt.typedarrays.shared.Float64Array;
+import com.google.gwt.typedarrays.shared.Int16Array;
+import com.google.gwt.typedarrays.shared.Int32Array;
+import com.google.gwt.typedarrays.shared.Int8Array;
+import com.google.gwt.typedarrays.shared.Uint16Array;
+import com.google.gwt.typedarrays.shared.Uint32Array;
+import com.google.gwt.typedarrays.shared.Uint8Array;
+import com.google.gwt.typedarrays.shared.Uint8ClampedArray;
+import com.google.gwt.typedarrays.shared.TypedArrays.Impl;
+
+/**
+ * The implementation class for browsers known to have no
+ * support (even emulated) for typed arrays.
+ */
+public class NoSupportImpl extends Impl {
+
+  @Override
+  public ArrayBuffer createArrayBuffer(int length) {
+    throw new UnsupportedOperationException("typed arrays not supported");
+  }
+
+  @Override
+  public DataView createDataView(ArrayBuffer buffer, int byteOffset,
+      int byteLength) {
+    throw new UnsupportedOperationException("typed arrays not supported");
+  }
+
+  @Override
+  public Float32Array createFloat32Array(ArrayBuffer buffer, int byteOffset, int length) {
+    throw new UnsupportedOperationException("typed arrays not supported");
+  }
+
+  @Override
+  public Float32Array createFloat32Array(float[] array) {
+    throw new UnsupportedOperationException("typed arrays not supported");
+  }
+
+  @Override
+  public Float64Array createFloat64Array(ArrayBuffer buffer, int byteOffset, int length) {
+    throw new UnsupportedOperationException("typed arrays not supported");
+  }
+
+  @Override
+  public Int16Array createInt16Array(ArrayBuffer buffer, int byteOffset, int length) {
+    throw new UnsupportedOperationException("typed arrays not supported");
+  }
+
+  @Override
+  public Int32Array createInt32Array(ArrayBuffer buffer, int byteOffset, int length) {
+    throw new UnsupportedOperationException("typed arrays not supported");
+  }
+
+  @Override
+  public Int8Array createInt8Array(ArrayBuffer buffer, int byteOffset, int length) {
+    throw new UnsupportedOperationException("typed arrays not supported");
+  }
+
+  @Override
+  public Uint16Array createUint16Array(ArrayBuffer buffer, int byteOffset, int length) {
+    throw new UnsupportedOperationException("typed arrays not supported");
+  }
+
+  @Override
+  public Uint32Array createUint32Array(ArrayBuffer buffer, int byteOffset, int length) {
+    throw new UnsupportedOperationException("typed arrays not supported");
+  }
+
+  @Override
+  public Uint8Array createUint8Array(ArrayBuffer buffer, int byteOffset, int length) {
+    throw new UnsupportedOperationException("typed arrays not supported");
+  }
+
+  @Override
+  public Uint8ClampedArray createUint8ClampedArray(ArrayBuffer buffer,
+      int byteOffset, int length) {
+    throw new UnsupportedOperationException("typed arrays not supported");
+  }
+
+  @Override
+  protected boolean mightBeSupported() {
+    return false;
+  }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/typedarrays/client/Uint16ArrayNative.java b/user/src/com/google/gwt/typedarrays/client/Uint16ArrayNative.java
new file mode 100644
index 0000000..3aff737
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/Uint16ArrayNative.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayUtils;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Uint16Array;
+
+/**
+ * JS native implementation of {@link Uint16Array}.
+ */
+public final class Uint16ArrayNative extends ArrayBufferViewNative implements Uint16Array {
+
+  /**
+   * @param buffer
+   * @return a {@link Uint16Array} instance
+   */
+  public static native Uint16ArrayNative create(ArrayBuffer buffer) /*-{
+    return new Uint16Array(buffer);
+  }-*/;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @return a {@link Uint16Array} instance
+   */
+  public static native Uint16ArrayNative create(ArrayBuffer buffer, int byteOffset) /*-{
+    return new Uint16Array(buffer, byteOffset);
+  }-*/;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   * @return a {@link Uint16Array} instance
+   */
+  public static native Uint16ArrayNative create(ArrayBuffer buffer, int byteOffset,
+      int length) /*-{
+    return new Uint16Array(buffer, byteOffset, length);
+  }-*/;
+
+  /**
+   * @param length
+   * @return a {@link Uint16Array} instance
+   */
+  public static native Uint16ArrayNative create(int length) /*-{
+    return new Uint16Array(length);
+  }-*/;
+
+  protected Uint16ArrayNative() {
+  }
+
+  @Override
+  public native int get(int index) /*-{
+    return this[index];
+  }-*/;
+
+  @Override
+  public native int length() /*-{
+    return this.length;
+  }-*/;
+
+  @Override
+  public native void set(int index, int value) /*-{
+    this[index] = value;
+  }-*/;
+
+  @Override
+  public void set(int[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(int[] array, int offset) {
+    set(JsArrayUtils.readOnlyJsArray(array), offset);
+  }
+
+  @Override
+  public native void set(Uint16Array array) /*-{
+    this.set(array);
+  }-*/;
+
+  @Override
+  public native void set(Uint16Array array, int offset) /*-{
+    this.set(array, offset);
+  }-*/;
+
+  @Override
+  public native Uint16Array subarray(int begin) /*-{
+    return this.subarray(begin);
+  }-*/;
+
+  @Override
+  public native Uint16Array subarray(int begin, int end) /*-{
+    return this.subarray(begin, end);
+  }-*/;
+
+  private native void set(JavaScriptObject array, int offset) /*-{
+    this.set(array, offset);
+  }-*/;
+}
diff --git a/user/src/com/google/gwt/typedarrays/client/Uint32ArrayNative.java b/user/src/com/google/gwt/typedarrays/client/Uint32ArrayNative.java
new file mode 100644
index 0000000..e99bd9b
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/Uint32ArrayNative.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayUtils;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Uint32Array;
+
+/**
+ * JS native implementation of {@link Uint32Array}.
+ */
+public final class Uint32ArrayNative extends ArrayBufferViewNative implements Uint32Array {
+
+  /**
+   * @param buffer
+   * @return a {@link Uint32Array} instance
+   */
+  public static native Uint32ArrayNative create(ArrayBuffer buffer) /*-{
+    return new Uint32Array(buffer);
+  }-*/;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @return a {@link Uint32Array} instance
+   */
+  public static native Uint32ArrayNative create(ArrayBuffer buffer, int byteOffset) /*-{
+    return new Uint32Array(buffer, byteOffset);
+  }-*/;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   * @return a {@link Uint32Array} instance
+   */
+  public static native Uint32ArrayNative create(ArrayBuffer buffer, int byteOffset,
+      int length) /*-{
+    return new Uint32Array(buffer, byteOffset, length);
+  }-*/;
+
+  /**
+   * @param length
+   * @return a {@link Uint32Array} instance
+   */
+  public static native Uint32ArrayNative create(int length) /*-{
+    return new Uint32Array(length);
+  }-*/;
+
+  protected Uint32ArrayNative() {
+  }
+
+  @Override
+  public long get(int index) {
+    return (long) getAsDouble(index);
+  }
+
+  @Override
+  public native double getAsDouble(int index) /*-{
+    return this[index];
+  }-*/;
+
+  @Override
+  public native int length() /*-{
+    return this.length;
+  }-*/;
+
+  @Override
+  public void set(double[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(double[] array, int offset) {
+    set(JsArrayUtils.readOnlyJsArray(array), offset);
+  }
+
+  @Override
+  public native void set(int index, double value) /*-{
+    this[index] = value;
+  }-*/;
+
+  @Override
+  public void set(int index, long value) {
+    set(index, (double) value);
+  }
+
+  @Override
+  public void set(long[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(long[] array, int offset) {
+    int len = array.length;
+    double[] temp = new double[len];
+    for (int i = 0; i < len; ++i) {
+      temp[i] = array[i];
+    }
+    set(temp, offset);
+  }
+
+  @Override
+  public native void set(Uint32Array array) /*-{
+    this.set(array);
+  }-*/;
+
+  @Override
+  public native void set(Uint32Array array, int offset) /*-{
+    this.set(array, offset);
+  }-*/;
+
+  @Override
+  public native Uint32Array subarray(int begin) /*-{
+    return this.subarray(begin);
+  }-*/;
+
+  @Override
+  public native Uint32Array subarray(int begin, int end) /*-{
+    return this.subarray(begin, end);
+  }-*/;
+
+  private native void set(JavaScriptObject array, int offset) /*-{
+    this.set(array, offset);
+  }-*/;
+}
diff --git a/user/src/com/google/gwt/typedarrays/client/Uint8ArrayNative.java b/user/src/com/google/gwt/typedarrays/client/Uint8ArrayNative.java
new file mode 100644
index 0000000..0f3ca93
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/Uint8ArrayNative.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayUtils;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Uint8Array;
+import com.google.gwt.typedarrays.shared.Uint8ClampedArray;
+
+/**
+ * JS native implementation of {@link Uint8Array} and, where natively supported,
+ * {@link Uint8ClampedArray}.
+ * <p>
+ * This should generally not be referenced directly -- see
+ * {@link com.google.gwt.typedarrays.shared.TypedArrays} and
+ * {@link com.google.gwt.typedarrays.client.JsUtils}.
+ */
+public final class Uint8ArrayNative extends ArrayBufferViewNative implements Uint8ClampedArray {
+
+  /**
+   * Create a {@link Uint8Array} instance.
+   * 
+   * @param buffer
+   * @return a {@link Uint8Array} instance
+   */
+  public static native Uint8ArrayNative create(ArrayBuffer buffer) /*-{
+    return new Uint8Array(buffer);
+  }-*/;
+
+  /**
+   * Create a {@link Uint8Array} instance.
+   * 
+   * @param buffer
+   * @param byteOffset
+   * @return a {@link Uint8Array} instance
+   */
+  public static native Uint8ArrayNative create(ArrayBuffer buffer, int byteOffset) /*-{
+    return new Uint8Array(buffer, byteOffset);
+  }-*/;
+
+  /**
+   * Create a {@link Uint8Array} instance.
+   * 
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   * @return a {@link Uint8Array} instance
+   */
+  public static native Uint8ArrayNative create(ArrayBuffer buffer, int byteOffset,
+      int length) /*-{
+    return new Uint8Array(buffer, byteOffset, length);
+  }-*/;
+
+  /**
+   * Create a {@link Uint8Array} instance.
+   * 
+   * @param length
+   * @return a {@link Uint8Array} instance
+   */
+  public static native Uint8ArrayNative create(int length) /*-{
+    return new Uint8Array(length);
+  }-*/;
+
+  /**
+   * Create a {@link Uint8Array} instance from an array.
+   * 
+   * @param array an array of initial values
+   * @return a {@link Uint8Array} instance
+   */
+  public static Uint8ArrayNative create(int[] array) {
+    return create(JsArrayUtils.readOnlyJsArray(array));
+  }
+
+  /**
+   * Create a {@link Uint8Array} instance from a JavaScript array-like object.
+   * 
+   * @param array a JS array or array-like object
+   * @return a {@link Uint8Array} instance
+   */
+  public static native Uint8ArrayNative create(JavaScriptObject array) /*-{
+    return new Uint8Array(array);
+  }-*/;
+
+  /**
+   * Create a {@link Uint8Array} instance from an array.
+   * 
+   * @param array an array of initial values
+   * @return a {@link Uint8Array} instance
+   */
+  public static Uint8ArrayNative create(short[] array) {
+    return create(JsArrayUtils.readOnlyJsArray(array));
+  }
+
+  /**
+   * Create a {@link Uint8ClampedArray} instance. Must only be called if the
+   * environment natively supports clamped arrays -- otherwise
+   * {@link Uint8ClampedArrayNativeEmul} should be used instead.
+   * 
+   * @param buffer
+   * @return a {@link Uint8Array} instance
+   */
+  public static native Uint8ArrayNative createClamped(ArrayBuffer buffer) /*-{
+    return new Uint8ClampedArray(buffer);
+  }-*/;
+
+  /**
+   * Create a {@link Uint8ClampedArray} instance. Must only be called if the
+   * environment natively supports clamped arrays -- otherwise
+   * {@link Uint8ClampedArrayNativeEmul} should be used instead.
+   * 
+   * @param buffer
+   * @param byteOffset
+   * @return a {@link Uint8Array} instance
+   */
+  public static native Uint8ArrayNative createClamped(ArrayBuffer buffer,
+      int byteOffset) /*-{
+    return new Uint8ClampedArray(buffer, byteOffset);
+  }-*/;
+
+  /**
+   * Create a {@link Uint8ClampedArray} instance. Must only be called if the
+   * environment natively supports clamped arrays -- otherwise
+   * {@link Uint8ClampedArrayNativeEmul} should be used instead.
+   * 
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   * @return a {@link Uint8Array} instance
+   */
+  public static native Uint8ArrayNative createClamped(ArrayBuffer buffer,
+      int byteOffset, int length) /*-{
+    return new Uint8ClampedArray(buffer, byteOffset, length);
+  }-*/;
+
+  /**
+   * Create a {@link Uint8ClampedArray} instance. Must only be called if the
+   * environment natively supports clamped arrays -- otherwise
+   * {@link Uint8ClampedArrayNativeEmul} should be used instead.
+   * 
+   * @param length
+   * @return a {@link Uint8Array} instance
+   */
+  public static native Uint8ArrayNative createClamped(int length) /*-{
+    return new Uint8ClampedArray(length);
+  }-*/;
+
+  /**
+   * Create a {@link Uint8Array} instance from an array. Must only be called if
+   * the environment natively supports clamped arrays -- otherwise
+   * {@link Uint8ClampedArrayNativeEmul} should be used instead.
+   * 
+   * @param array an array of initial values
+   * @return a {@link Uint8Array} instance
+   */
+  public static Uint8ArrayNative createClamped(int[] array) {
+    return createClamped(JsArrayUtils.readOnlyJsArray(array));
+  }
+
+  /**
+   * Create a {@link Uint8ClampedArray} instance from a JavaScript array-like
+   * object. Must only be called if the environment natively supports clamped
+   * arrays -- otherwise {@link Uint8ClampedArrayNativeEmul} should be used
+   * instead.
+   * 
+   * @param array a JS array or array-like object
+   * @return a {@link Uint8ClampedArray} instance
+   */
+  public static native Uint8ArrayNative createClamped(JavaScriptObject array) /*-{
+    return new Uint8ClampedArray(array);
+  }-*/;
+
+  /**
+   * Create a {@link Uint8Array} instance from an array. Must only be called if
+   * the environment natively supports clamped arrays -- otherwise
+   * {@link Uint8ClampedArrayNativeEmul} should be used instead.
+   * 
+   * @param array an array of initial values
+   * @return a {@link Uint8Array} instance
+   */
+  public static Uint8ArrayNative createClamped(short[] array) {
+    return createClamped(JsArrayUtils.readOnlyJsArray(array));
+  }
+
+  protected Uint8ArrayNative() {
+  }
+
+  @Override
+  public native short get(int index) /*-{
+    return this[index];
+  }-*/;
+
+  @Override
+  public native int length() /*-{
+    return this.length;
+  }-*/;
+
+  @Override
+  public native void set(int index, int value) /*-{
+    this[index] = value;
+  }-*/;
+
+  @Override
+  public void set(int[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(int[] array, int offset) {
+    set(JsArrayUtils.readOnlyJsArray(array), offset);
+  }
+
+  @Override
+  public void set(short[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(short[] array, int offset) {
+    set(JsArrayUtils.readOnlyJsArray(array), offset);
+  }
+
+  @Override
+  public void set(Uint8Array array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(Uint8Array array, int offset) {
+    if (array instanceof Uint8ArrayNative) {
+      // Note that any JSO would pass this check, but since only one JSO can
+      // implement a given interface it has to be this one, so any other
+      // implementations must be Java emulations.
+      setNative(array, offset);
+      return;
+    }
+    int len = array.length();
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array.get(i));
+    }
+  }
+
+  @Override
+  public native Uint8ArrayNative subarray(int begin) /*-{
+    return this.subarray(begin);
+  }-*/;
+
+  @Override
+  public native Uint8ArrayNative subarray(int begin, int end) /*-{
+    return this.subarray(begin, end);
+  }-*/;
+
+  private native void set(JavaScriptObject array, int offset) /*-{
+    this.set(array, offset);
+  }-*/;
+
+  /**
+   * Called when {@code array} is known to be a native {@link Uint8Array}
+   * implementation.
+   * 
+   * @param array
+   * @param offset
+   */
+  private native void setNative(Uint8Array array, int offset) /*-{
+    this.set(array, offset);
+  }-*/;
+}
diff --git a/user/src/com/google/gwt/typedarrays/client/Uint8ClampedArrayNativeEmul.java b/user/src/com/google/gwt/typedarrays/client/Uint8ClampedArrayNativeEmul.java
new file mode 100644
index 0000000..ad5f26d
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/client/Uint8ClampedArrayNativeEmul.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JsArrayInteger;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Uint8Array;
+import com.google.gwt.typedarrays.shared.Uint8ClampedArray;
+
+/**
+ * Emulated version of {@link Uint8ClampedArray} that is implemented using a {@link Uint8Array}.
+ */
+public class Uint8ClampedArrayNativeEmul implements Uint8ClampedArray {
+
+  /**
+   * Create a {@link Uint8ClampedArray} instance on an existing
+   * {@link ArrayBuffer}.
+   * 
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   * @return {@link Uint8ClampedArray} instance
+   */
+  public static Uint8ClampedArray create(ArrayBuffer buffer, int byteOffset, int length) {
+    return new Uint8ClampedArrayNativeEmul(buffer, byteOffset, length);
+  }
+
+  /**
+   * Create a {@link Uint8ClampedArray} instance from a short array.
+   * 
+   * @param array
+   * @return {@link Uint8ClampedArray} instance
+   */
+  public static Uint8ClampedArray create(short[] array) {
+    int len = array.length;
+    Uint8ClampedArray result = create(ArrayBufferNative.create(len), 0, len);
+    result.set(array);
+    return result;
+  }
+
+  /**
+   * Create a {@link Uint8ClampedArray} instance from a JavaScript array
+   * containing integers.
+   * 
+   * @param array JavaScript array object
+   * @return {@link Uint8ClampedArray} instance
+   */
+  public static Uint8ClampedArray create(JsArrayInteger array) {
+    int len = array.length();
+    Uint8ClampedArray result = create(ArrayBufferNative.create(len), 0, len);
+    JsUtils.set(result, array);
+    return result;
+  }
+
+  private static short clamp(int val) {
+    return (short) Math.max(0, Math.min(val, 255));
+  }
+
+  private final Uint8Array real;
+
+  /**
+   * Internal constructor for creating an {@link Uint8ClampedArrayNativeEmul}
+   * on an existing {@link ArrayBuffer} instance. 
+   * 
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   */
+  protected Uint8ClampedArrayNativeEmul(ArrayBuffer buffer, int byteOffset, int length) {
+    real = Uint8ArrayNative.create(buffer, byteOffset, length);
+  }
+
+  @Override
+  public ArrayBuffer buffer() {
+    return real.buffer();
+  }
+
+  @Override
+  public int byteLength() {
+    return real.byteLength();
+  }
+
+  @Override
+  public int byteOffset() {
+    return real.byteOffset();
+  }
+
+  @Override
+  public short get(int index) {
+    return real.get(index);
+  }
+
+  @Override
+  public int length() {
+    return real.length();
+  }
+
+  @Override
+  public void set(int index, int value) {
+    real.set(index, clamp(value));
+  }
+
+  @Override
+  public void set(int[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(int[] array, int offset) {
+    int len = array.length;
+    for (int i = 0; i < len; ++i) {
+      real.set(offset++, clamp(array[i]));
+    }
+  }
+
+  @Override
+  public void set(short[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(short[] array, int offset) {
+    int len = array.length;
+    for (int i = 0; i < len; ++i) {
+      real.set(offset++, clamp(array[i]));
+    }
+  }
+
+  @Override
+  public void set(Uint8Array array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(Uint8Array array, int offset) {
+    int len = array.length();
+    for (int i = 0; i < len; ++i) {
+      real.set(offset++, clamp(array.get(i)));
+    }
+  }
+
+  @Override
+  public Uint8ClampedArray subarray(int begin) {
+    return subarray(begin, byteLength());
+  }
+
+  @Override
+  public Uint8ClampedArray subarray(int begin, int end) {
+    int len = byteLength();
+    if (begin < 0) {
+      begin += len;
+    }
+    if (end < 0) {
+      end += len;
+    }
+    if (begin < 0) {
+      begin = 0;
+    } else if (begin > len) {
+      begin = len;
+    }
+    if (end < begin) {
+      end = begin;
+    } else if (end > len) {
+      end = len;
+    }
+    return new Uint8ClampedArrayNativeEmul(buffer(), byteOffset() + begin, end - begin);
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/server/ArrayBufferImpl.java b/user/src/com/google/gwt/typedarrays/server/ArrayBufferImpl.java
new file mode 100644
index 0000000..0119c35
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/server/ArrayBufferImpl.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.server;
+
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Pure Java implementation of {@link ArrayBuffer}, plus package-protected methods
+ * for use by related implementation classes.
+ */
+public class ArrayBufferImpl implements ArrayBuffer {
+
+  private final Object lock = new Object();
+
+  private final ByteBuffer buf;
+
+  /**
+   * @param length
+   */
+  public ArrayBufferImpl(int length) {
+    buf = ByteBuffer.allocate(length);
+    // JS lets native byte order show through, which is typically little-endian
+    // so if there is code that incorrectly assumes anything, it will be
+    // little-endian.
+    buf.order(ByteOrder.LITTLE_ENDIAN);
+  }
+
+  @Override
+  public int byteLength() {
+    return buf.capacity();
+  }
+
+  float getFloat32(int byteOffset, boolean littleEndian) {
+    synchronized (lock) {
+      try {
+        if (!littleEndian) {
+          buf.order(ByteOrder.BIG_ENDIAN);
+        }
+        return buf.getFloat(byteOffset);
+      } finally {
+        if (!littleEndian) {
+          buf.order(ByteOrder.LITTLE_ENDIAN);
+        }
+      }
+    }
+  }
+
+  double getFloat64(int byteOffset, boolean littleEndian) {
+    synchronized (lock) {
+      try {
+        if (!littleEndian) {
+          buf.order(ByteOrder.BIG_ENDIAN);
+        }
+        return buf.getDouble(byteOffset);
+      } finally {
+        if (!littleEndian) {
+          buf.order(ByteOrder.LITTLE_ENDIAN);
+        }
+      }
+    }
+  }
+
+  short getInt16(int byteOffset, boolean littleEndian) {
+    synchronized (lock) {
+      try {
+        if (!littleEndian) {
+          buf.order(ByteOrder.BIG_ENDIAN);
+        }
+        return buf.getShort(byteOffset);
+      } finally {
+        if (!littleEndian) {
+          buf.order(ByteOrder.LITTLE_ENDIAN);
+        }
+      }
+    }
+  }
+
+  int getInt32(int byteOffset, boolean littleEndian) {
+    synchronized (lock) {
+      try {
+        if (!littleEndian) {
+          buf.order(ByteOrder.BIG_ENDIAN);
+        }
+        return buf.getInt(byteOffset);
+      } finally {
+        if (!littleEndian) {
+          buf.order(ByteOrder.LITTLE_ENDIAN);
+        }
+      }
+    }
+  }
+
+  byte getInt8(int byteOffset) {
+    return buf.get(byteOffset);
+  }
+
+  void setFloat32(int byteOffset, float value, boolean littleEndian) {
+    synchronized (lock) {
+      try {
+        if (!littleEndian) {
+          buf.order(ByteOrder.BIG_ENDIAN);
+        }
+        buf.putFloat(byteOffset, value);
+      } finally {
+        if (!littleEndian) {
+          buf.order(ByteOrder.LITTLE_ENDIAN);
+        }
+      }
+    }
+  }
+
+  void setFloat64(int byteOffset, double value, boolean littleEndian) {
+    synchronized (lock) {
+      try {
+        if (!littleEndian) {
+          buf.order(ByteOrder.BIG_ENDIAN);
+        }
+        buf.putDouble(byteOffset, value);
+      } finally {
+        if (!littleEndian) {
+          buf.order(ByteOrder.LITTLE_ENDIAN);
+        }
+      }
+    }
+  }
+
+  void setInt16(int byteOffset, short value, boolean littleEndian) {
+    synchronized (lock) {
+      try {
+        if (!littleEndian) {
+          buf.order(ByteOrder.BIG_ENDIAN);
+        }
+        buf.putShort(byteOffset, value);
+      } finally {
+        if (!littleEndian) {
+          buf.order(ByteOrder.LITTLE_ENDIAN);
+        }
+      }
+    }
+  }
+
+  void setInt32(int byteOffset, int value, boolean littleEndian) {
+    synchronized (lock) {
+      try {
+        if (!littleEndian) {
+          buf.order(ByteOrder.BIG_ENDIAN);
+        }
+        buf.putInt(byteOffset, value);
+      } finally {
+        if (!littleEndian) {
+          buf.order(ByteOrder.LITTLE_ENDIAN);
+        }
+      }
+    }
+  }
+
+  void setInt8(int byteOffset, byte value) {
+    buf.put(byteOffset, value);
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/server/ArrayBufferViewImpl.java b/user/src/com/google/gwt/typedarrays/server/ArrayBufferViewImpl.java
new file mode 100644
index 0000000..02a4e4f
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/server/ArrayBufferViewImpl.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.server;
+
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.ArrayBufferView;
+
+/**
+ * Base class for {@link ArrayBufferView} implementations.
+ */
+public abstract class ArrayBufferViewImpl implements ArrayBufferView {
+
+  /**
+   * The spec lets the platform's native endianness come through, so we choose to
+   * expose little-endian regardless -- if apps care about the endianness but don't
+   * test for it, it is likely they assume little-endian.
+   */
+  static final boolean USE_LITTLE_ENDIAN = true;
+
+  protected final ArrayBufferImpl arrayBuf;
+  protected final int byteLength;
+  protected final int byteOffset;
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param byteLength
+   */
+  public ArrayBufferViewImpl(ArrayBuffer buffer, int byteOffset, int byteLength) {
+    if (!(buffer instanceof ArrayBufferImpl)) {
+      throw new UnsupportedOperationException("Unacceptable ArrayBuffer type");
+    }
+    this.arrayBuf = (ArrayBufferImpl) buffer;
+    this.byteOffset = byteOffset;
+    this.byteLength = byteLength;
+  }
+
+  @Override
+  public ArrayBuffer buffer() {
+    return arrayBuf;
+  }
+
+  @Override
+  public int byteLength() {
+    return byteLength;
+  }
+
+  @Override
+  public int byteOffset() {
+    return byteOffset;
+  }
+
+  /**
+   * Check the index range and throw an exception if out of range, if ok return the
+   * byte index of the specified element.
+   * 
+   * @param index an element index
+   * @param bytesPerElement
+   * @return the byte index of the start of this element
+   */
+  protected int checkRange(int index, int bytesPerElement) {
+    int byteIndex = index * bytesPerElement;
+    if (byteIndex < byteOffset || byteIndex + bytesPerElement > byteLength) {
+      throw new ArrayIndexOutOfBoundsException(index);
+    }
+    return byteIndex;
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/server/DataViewImpl.java b/user/src/com/google/gwt/typedarrays/server/DataViewImpl.java
new file mode 100644
index 0000000..3822e33
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/server/DataViewImpl.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.server;
+
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.DataView;
+
+/**
+ * Pure Java implementation of {@link DataView}.
+ */
+public class DataViewImpl extends ArrayBufferViewImpl implements DataView {
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param byteLength
+   */
+  public DataViewImpl(ArrayBuffer buffer, int byteOffset, int byteLength) {
+    super(buffer, byteOffset, byteLength);
+  }
+
+  @Override
+  public float getFloat32(int byteOffset) {
+    return getFloat32(byteOffset, false);
+  }
+
+  @Override
+  public float getFloat32(int byteOffset, boolean littleEndian) {
+    return arrayBuf.getFloat32(byteOffset, littleEndian);
+  }
+
+  @Override
+  public double getFloat64(int byteOffset) {
+    return getFloat64(byteOffset, false);
+  }
+
+  @Override
+  public double getFloat64(int byteOffset, boolean littleEndian) {
+    return arrayBuf.getFloat64(byteOffset, littleEndian);
+  }
+
+  @Override
+  public short getInt16(int byteOffset) {
+    return getInt16(byteOffset, false);
+  }
+
+  @Override
+  public short getInt16(int byteOffset, boolean littleEndian) {
+    return arrayBuf.getInt16(byteOffset, littleEndian);
+  }
+
+  @Override
+  public int getInt32(int byteOffset) {
+    return getInt32(byteOffset, false);
+  }
+
+  @Override
+  public int getInt32(int byteOffset, boolean littleEndian) {
+    return arrayBuf.getInt32(byteOffset, littleEndian);
+  }
+
+  @Override
+  public byte getInt8(int byteOffset) {
+    return arrayBuf.getInt8(byteOffset);
+  }
+
+  @Override
+  public int getUint16(int byteOffset) {
+    return getUint16(byteOffset, false);
+  }
+
+  @Override
+  public int getUint16(int byteOffset, boolean littleEndian) {
+    int val = arrayBuf.getInt16(byteOffset, littleEndian);
+    if (val < 0) {
+      val += 0x10000;
+    }
+    return val;
+  }
+
+  @Override
+  public long getUint32(int byteOffset) {
+    return getUint32(byteOffset, false);
+  }
+
+  @Override
+  public long getUint32(int byteOffset, boolean littleEndian) {
+    long val = arrayBuf.getInt32(byteOffset, littleEndian);
+    if (val < 0) {
+      val += 0x100000000L;
+    }
+    return val;
+  }
+
+  @Override
+  public double getUint32AsDouble(int byteOffset) {
+    return getUint32(byteOffset, false);
+  }
+
+  @Override
+  public double getUint32AsDouble(int byteOffset, boolean littleEndian) {
+    return getUint32(byteOffset, littleEndian);
+  }
+
+  @Override
+  public short getUint8(int byteOffset) {
+    short val = getInt8(byteOffset);
+    if (val < 0) {
+      val += 256;
+    }
+    return val;
+  }
+
+  @Override
+  public void setFloat32(int byteOffset, float value) {
+    setFloat32(byteOffset, value, false);
+  }
+
+  @Override
+  public void setFloat32(int byteOffset, float value, boolean littleEndian) {
+    arrayBuf.setFloat32(byteOffset, value, littleEndian);
+  }
+
+  @Override
+  public void setFloat64(int byteOffset, double value) {
+    setFloat64(byteOffset, value, false);
+  }
+
+  @Override
+  public void setFloat64(int byteOffset, double value, boolean littleEndian) {
+    arrayBuf.setFloat64(byteOffset, value, littleEndian);
+  }
+
+  @Override
+  public void setInt16(int byteOffset, int value) {
+    setInt16(byteOffset, value, false);
+  }
+
+  @Override
+  public void setInt16(int byteOffset, int value, boolean littleEndian) {
+    arrayBuf.setInt16(byteOffset, (short) (value & 0xFFFF), littleEndian);
+  }
+
+  @Override
+  public void setInt32(int byteOffset, int value) {
+    setInt32(byteOffset, value, false);
+  }
+
+  @Override
+  public void setInt32(int byteOffset, int value, boolean littleEndian) {
+    arrayBuf.setInt32(byteOffset, value, littleEndian);
+  }
+
+  @Override
+  public void setInt8(int byteOffset, int value) {
+    arrayBuf.setInt8(byteOffset, (byte) (value & 255));
+  }
+
+  @Override
+  public void setUint16(int byteOffset, int value) {
+    setUint16(byteOffset, value, false);
+  }
+
+  @Override
+  public void setUint16(int byteOffset, int value, boolean littleEndian) {
+    arrayBuf.setInt16(byteOffset, (short) (value & 0xFFFF), littleEndian);
+  }
+
+  @Override
+  public void setUint32(int byteOffset, long value) {
+    setUint32(byteOffset, value, false);
+  }
+
+  @Override
+  public void setUint32(int byteOffset, long value, boolean littleEndian) {
+    arrayBuf.setInt32(byteOffset, (int) (value & 0xFFFFFFFF), littleEndian);
+  }
+
+  @Override
+  public void setUint32FromDouble(int byteOffset, double value) {
+    setUint32(byteOffset, (long) value);
+  }
+
+  @Override
+  public void setUint32FromDouble(int byteOffset, double value, boolean littleEndian) {
+    setUint32(byteOffset, (long) value, littleEndian);
+  }
+
+  @Override
+  public void setUint8(int byteOffset, int value) {
+    arrayBuf.setInt8(byteOffset, (byte) (value & 255));
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/server/Float32ArrayImpl.java b/user/src/com/google/gwt/typedarrays/server/Float32ArrayImpl.java
new file mode 100644
index 0000000..3c7f2a5
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/server/Float32ArrayImpl.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.server;
+
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Float32Array;
+
+/**
+ * Pure Java implementation of {@link Float32Array}.
+ */
+public final class Float32ArrayImpl extends ArrayBufferViewImpl implements Float32Array {
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   */
+  public Float32ArrayImpl(ArrayBuffer buffer, int byteOffset, int length) {
+    super(buffer, byteOffset, length * BYTES_PER_ELEMENT);
+  }
+
+  @Override
+  public float get(int index) {
+    return arrayBuf.getFloat32(checkRange(index, BYTES_PER_ELEMENT), USE_LITTLE_ENDIAN);
+  }
+
+  @Override
+  public int length() {
+    return byteLength() / BYTES_PER_ELEMENT;
+  }
+
+  @Override
+  public void set(float[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(float[] array, int offset) {
+    int len = array.length;
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array[i]);
+    }
+  }
+
+  @Override
+  public void set(Float32Array array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(Float32Array array, int offset) {
+    int len = array.length();
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array.get(i));
+    }
+  }
+
+  @Override
+  public void set(int index, float value) {
+    arrayBuf.setFloat32(checkRange(index, BYTES_PER_ELEMENT), value, USE_LITTLE_ENDIAN);
+  }
+
+  @Override
+  public Float32Array subarray(int begin) {
+    int count = (byteLength() - byteOffset()) / BYTES_PER_ELEMENT;
+    return subarray(begin, count);
+  }
+
+  @Override
+  public Float32Array subarray(int begin, int end) {
+    int count = (byteLength() - byteOffset()) / BYTES_PER_ELEMENT;
+    if (begin < 0) {
+      begin += count;
+      if (begin < 0) {
+        begin = 0;
+      }
+    } else if (begin > count) {
+      begin = count;
+    }
+    if (end < 0) {
+      end += count;
+      if (end < 0) {
+        end = 0;
+      }
+    } else if (end > count) {
+      end = count;
+    }
+    if (end < begin) {
+      end = begin;
+    }
+    return new Float32ArrayImpl(arrayBuf, begin * BYTES_PER_ELEMENT, end * BYTES_PER_ELEMENT);
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/server/Float64ArrayImpl.java b/user/src/com/google/gwt/typedarrays/server/Float64ArrayImpl.java
new file mode 100644
index 0000000..7dcf6fd
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/server/Float64ArrayImpl.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.server;
+
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Float64Array;
+
+/**
+ * Pure Java implementation of {@link Float64Array}.
+ */
+public final class Float64ArrayImpl extends ArrayBufferViewImpl implements Float64Array {
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   */
+  public Float64ArrayImpl(ArrayBuffer buffer, int byteOffset, int length) {
+    super(buffer, byteOffset, length * BYTES_PER_ELEMENT);
+  }
+
+  @Override
+  public double get(int index) {
+    return arrayBuf.getFloat64(checkRange(index, BYTES_PER_ELEMENT), USE_LITTLE_ENDIAN);
+  }
+  
+  @Override
+  public int length() {
+    return byteLength() / BYTES_PER_ELEMENT;
+  }
+
+  @Override
+  public void set(double[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(double[] array, int offset) {
+    int len = array.length;
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array[i]);
+    }
+  }
+
+  @Override
+  public void set(Float64Array array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(Float64Array array, int offset) {
+    int len = array.length();
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array.get(i));
+    }
+  }
+
+  @Override
+  public void set(int index, double value) {
+    arrayBuf.setFloat64(checkRange(index, BYTES_PER_ELEMENT), value, USE_LITTLE_ENDIAN);
+  }
+
+  @Override
+  public Float64Array subarray(int begin) {
+    int count = (byteLength() - byteOffset()) / BYTES_PER_ELEMENT;
+    return subarray(begin, count);
+  }
+
+  @Override
+  public Float64Array subarray(int begin, int end) {
+    int count = (byteLength() - byteOffset()) / BYTES_PER_ELEMENT;
+    if (begin < 0) {
+      begin += count;
+      if (begin < 0) {
+        begin = 0;
+      }
+    } else if (begin > count) {
+      begin = count;
+    }
+    if (end < 0) {
+      end += count;
+      if (end < 0) {
+        end = 0;
+      }
+    } else if (end > count) {
+      end = count;
+    }
+    if (end < begin) {
+      end = begin;
+    }
+    return new Float64ArrayImpl(arrayBuf, begin * BYTES_PER_ELEMENT, end * BYTES_PER_ELEMENT);
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/server/Int16ArrayImpl.java b/user/src/com/google/gwt/typedarrays/server/Int16ArrayImpl.java
new file mode 100644
index 0000000..560451a
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/server/Int16ArrayImpl.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.server;
+
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Int16Array;
+
+/**
+ * Pure Java implementation of {@link Int16Array}.
+ */
+public final class Int16ArrayImpl extends ArrayBufferViewImpl implements Int16Array {
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   */
+  public Int16ArrayImpl(ArrayBuffer buffer, int byteOffset, int length) {
+    super(buffer, byteOffset, length * BYTES_PER_ELEMENT);
+  }
+
+  @Override
+  public short get(int index) {
+    return arrayBuf.getInt16(checkRange(index, BYTES_PER_ELEMENT), USE_LITTLE_ENDIAN);
+  }
+
+  @Override
+  public int length() {
+    return byteLength() / BYTES_PER_ELEMENT;
+  }
+
+  @Override
+  public void set(int index, int value) {
+    arrayBuf.setInt16(checkRange(index, BYTES_PER_ELEMENT), (short) (value & 0xFFFF),
+        USE_LITTLE_ENDIAN);
+  }
+
+  @Override
+  public void set(int[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(int[] array, int offset) {
+    int len = array.length;
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array[i]);
+    }
+  }
+
+  @Override
+  public void set(Int16Array array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(Int16Array array, int offset) {
+    int len = array.length();
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array.get(i));
+    }
+  }
+
+  @Override
+  public void set(short[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(short[] array, int offset) {
+    int len = array.length;
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array[i]);
+    }
+  }
+
+  @Override
+  public Int16Array subarray(int begin) {
+    int count = (byteLength() - byteOffset()) / BYTES_PER_ELEMENT;
+    return subarray(begin, count);
+  }
+
+  @Override
+  public Int16Array subarray(int begin, int end) {
+    int count = (byteLength() - byteOffset()) / BYTES_PER_ELEMENT;
+    if (begin < 0) {
+      begin += count;
+      if (begin < 0) {
+        begin = 0;
+      }
+    } else if (begin > count) {
+      begin = count;
+    }
+    if (end < 0) {
+      end += count;
+      if (end < 0) {
+        end = 0;
+      }
+    } else if (end > count) {
+      end = count;
+    }
+    if (end < begin) {
+      end = begin;
+    }
+    return new Int16ArrayImpl(arrayBuf, begin * BYTES_PER_ELEMENT, end * BYTES_PER_ELEMENT);
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/server/Int32ArrayImpl.java b/user/src/com/google/gwt/typedarrays/server/Int32ArrayImpl.java
new file mode 100644
index 0000000..1b337d8
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/server/Int32ArrayImpl.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.server;
+
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Int32Array;
+
+/**
+ * Pure Java implementation of {@link Int32Array}.
+ */
+public final class Int32ArrayImpl extends ArrayBufferViewImpl implements Int32Array {
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   */
+  public Int32ArrayImpl(ArrayBuffer buffer, int byteOffset, int length) {
+    super(buffer, byteOffset, length * BYTES_PER_ELEMENT);
+  }
+
+  @Override
+  public int get(int index) {
+    return arrayBuf.getInt32(checkRange(index, BYTES_PER_ELEMENT), USE_LITTLE_ENDIAN);
+  }
+
+  @Override
+  public int length() {
+    return byteLength() / BYTES_PER_ELEMENT;
+  }
+
+  @Override
+  public void set(int index, int value) {
+    arrayBuf.setInt32(checkRange(index, BYTES_PER_ELEMENT), value, USE_LITTLE_ENDIAN);
+  }
+
+  @Override
+  public void set(int[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(int[] array, int offset) {
+    int len = array.length;
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array[i]);
+    }
+  }
+
+  @Override
+  public void set(Int32Array array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(Int32Array array, int offset) {
+    int len = array.length();
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array.get(i));
+    }
+  }
+
+  @Override
+  public Int32Array subarray(int begin) {
+    int count = (byteLength() - byteOffset()) / BYTES_PER_ELEMENT;
+    return subarray(begin, count);
+  }
+
+  @Override
+  public Int32Array subarray(int begin, int end) {
+    int count = (byteLength() - byteOffset()) / BYTES_PER_ELEMENT;
+    if (begin < 0) {
+      begin += count;
+      if (begin < 0) {
+        begin = 0;
+      }
+    } else if (begin > count) {
+      begin = count;
+    }
+    if (end < 0) {
+      end += count;
+      if (end < 0) {
+        end = 0;
+      }
+    } else if (end > count) {
+      end = count;
+    }
+    if (end < begin) {
+      end = begin;
+    }
+    return new Int32ArrayImpl(arrayBuf, begin * BYTES_PER_ELEMENT, end * BYTES_PER_ELEMENT);
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/server/Int8ArrayImpl.java b/user/src/com/google/gwt/typedarrays/server/Int8ArrayImpl.java
new file mode 100644
index 0000000..1415c7d
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/server/Int8ArrayImpl.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.server;
+
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Int8Array;
+
+/**
+ * Pure Java implementation of {@link Int8Array}.
+ */
+public final class Int8ArrayImpl extends ArrayBufferViewImpl implements Int8Array {
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param byteLength
+   */
+  public Int8ArrayImpl(ArrayBuffer buffer, int byteOffset, int byteLength) {
+    super(buffer, byteOffset, byteLength);
+  }
+
+  @Override
+  public byte get(int index) {
+    return arrayBuf.getInt8(checkRange(index, BYTES_PER_ELEMENT));
+  }
+
+  @Override
+  public int length() {
+    return byteLength() / BYTES_PER_ELEMENT;
+  }
+
+  @Override
+  public void set(byte[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(byte[] array, int offset) {
+    int len = array.length;
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array[i]);
+    }
+  }
+
+  @Override
+  public void set(int index, int value) {
+    arrayBuf.setInt8(checkRange(index, BYTES_PER_ELEMENT), (byte) (value & 0xFF));
+  }
+
+  @Override
+  public void set(int[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(int[] array, int offset) {
+    int len = array.length;
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array[i]);
+    }
+  }
+
+  @Override
+  public void set(Int8Array array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(Int8Array array, int offset) {
+    int len = array.length();
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array.get(i));
+    }
+  }
+
+  @Override
+  public Int8Array subarray(int begin) {
+    int count = (byteLength() - byteOffset()) / BYTES_PER_ELEMENT;
+    return subarray(begin, count);
+  }
+
+  @Override
+  public Int8Array subarray(int begin, int end) {
+    int count = (byteLength() - byteOffset()) / BYTES_PER_ELEMENT;
+    if (begin < 0) {
+      begin += count;
+      if (begin < 0) {
+        begin = 0;
+      }
+    } else if (begin > count) {
+      begin = count;
+    }
+    if (end < 0) {
+      end += count;
+      if (end < 0) {
+        end = 0;
+      }
+    } else if (end > count) {
+      end = count;
+    }
+    if (end < begin) {
+      end = begin;
+    }
+    return new Int8ArrayImpl(arrayBuf, begin * BYTES_PER_ELEMENT, end * BYTES_PER_ELEMENT);
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/server/JavaImpl.java b/user/src/com/google/gwt/typedarrays/server/JavaImpl.java
new file mode 100644
index 0000000..03f92f5
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/server/JavaImpl.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.server;
+
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.DataView;
+import com.google.gwt.typedarrays.shared.Float32Array;
+import com.google.gwt.typedarrays.shared.Float64Array;
+import com.google.gwt.typedarrays.shared.Int16Array;
+import com.google.gwt.typedarrays.shared.Int32Array;
+import com.google.gwt.typedarrays.shared.Int8Array;
+import com.google.gwt.typedarrays.shared.TypedArrays;
+import com.google.gwt.typedarrays.shared.TypedArrays.Impl;
+import com.google.gwt.typedarrays.shared.Uint16Array;
+import com.google.gwt.typedarrays.shared.Uint32Array;
+import com.google.gwt.typedarrays.shared.Uint8Array;
+import com.google.gwt.typedarrays.shared.Uint8ClampedArray;
+
+/**
+ * Pure Java implementation class for typed arrays.
+ */
+public class JavaImpl extends Impl {
+
+  @Override
+  public ArrayBuffer createArrayBuffer(int length) {
+    return new ArrayBufferImpl(length);
+  }
+
+  @Override
+  public DataView createDataView(ArrayBuffer buffer, int byteOffset, int byteLength) {
+    return new DataViewImpl(buffer, byteOffset, byteLength);
+  }
+
+  @Override
+  public Float32Array createFloat32Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return new Float32ArrayImpl(buffer, byteOffset, length);
+  }
+
+  @Override
+  public Float32Array createFloat32Array(float[] array) {
+    Float32Array result = TypedArrays.createFloat32Array(array.length);
+    result.set(array);
+    return result;
+  }
+
+  @Override
+  public Float64Array createFloat64Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return new Float64ArrayImpl(buffer, byteOffset, length);
+  }
+
+  @Override
+  public Int16Array createInt16Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return new Int16ArrayImpl(buffer, byteOffset, length);
+  }
+
+  @Override
+  public Int32Array createInt32Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return new Int32ArrayImpl(buffer, byteOffset, length);
+  }
+
+  @Override
+  public Int8Array createInt8Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return new Int8ArrayImpl(buffer, byteOffset, length);
+  }
+
+  @Override
+  public Uint16Array createUint16Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return new Uint16ArrayImpl(buffer, byteOffset, length);
+  }
+
+  @Override
+  public Uint32Array createUint32Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return new Uint32ArrayImpl(buffer, byteOffset, length);
+  }
+
+  @Override
+  public Uint8Array createUint8Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return new Uint8ArrayImpl(buffer, byteOffset, length);
+  }
+
+  @Override
+  public Uint8ClampedArray createUint8ClampedArray(ArrayBuffer buffer, int byteOffset, int length) {
+    return new Uint8ClampedArrayImpl(buffer, byteOffset, length);
+  }
+
+  @Override
+  protected boolean runtimeSupportCheck() {
+    return true;
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/server/Uint16ArrayImpl.java b/user/src/com/google/gwt/typedarrays/server/Uint16ArrayImpl.java
new file mode 100644
index 0000000..2eb260a
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/server/Uint16ArrayImpl.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.server;
+
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Uint16Array;
+
+/**
+ * Pure Java implementation of {@link Uint16Array}.
+ */
+public class Uint16ArrayImpl extends ArrayBufferViewImpl implements Uint16Array {
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   */
+  public Uint16ArrayImpl(ArrayBuffer buffer, int byteOffset, int length) {
+    super(buffer, byteOffset, length * BYTES_PER_ELEMENT);
+  }
+
+  @Override
+  public int get(int index) {
+    int val = arrayBuf.getInt8(checkRange(index, BYTES_PER_ELEMENT));
+    if (val < 0) {
+      val += 0x10000;
+    }
+    return val;
+  }
+
+  @Override
+  public int length() {
+    return byteLength() / BYTES_PER_ELEMENT;
+  }
+
+  @Override
+  public void set(int index, int value) {
+    arrayBuf.setInt16(checkRange(index, BYTES_PER_ELEMENT), (short) (value & 0xFFFF),
+        USE_LITTLE_ENDIAN);
+  }
+
+  @Override
+  public void set(int[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(int[] array, int offset) {
+    int len = array.length;
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array[i]);
+    }
+  }
+
+  @Override
+  public void set(Uint16Array array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(Uint16Array array, int offset) {
+    int len = array.length();
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array.get(i));
+    }
+  }
+
+  @Override
+  public Uint16Array subarray(int begin) {
+    int count = (byteLength() - byteOffset()) / BYTES_PER_ELEMENT;
+    return subarray(begin, count);
+  }
+
+  @Override
+  public Uint16Array subarray(int begin, int end) {
+    int count = (byteLength() - byteOffset()) / BYTES_PER_ELEMENT;
+    if (begin < 0) {
+      begin += count;
+      if (begin < 0) {
+        begin = 0;
+      }
+    } else if (begin > count) {
+      begin = count;
+    }
+    if (end < 0) {
+      end += count;
+      if (end < 0) {
+        end = 0;
+      }
+    } else if (end > count) {
+      end = count;
+    }
+    if (end < begin) {
+      end = begin;
+    }
+    return new Uint16ArrayImpl(arrayBuf, begin * BYTES_PER_ELEMENT, end * BYTES_PER_ELEMENT);
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/server/Uint32ArrayImpl.java b/user/src/com/google/gwt/typedarrays/server/Uint32ArrayImpl.java
new file mode 100644
index 0000000..80b6290
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/server/Uint32ArrayImpl.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.server;
+
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Uint32Array;
+
+/**
+ * Pure Java implementation of {@link Uint32Array}.
+ */
+public class Uint32ArrayImpl extends ArrayBufferViewImpl implements Uint32Array {
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   */
+  public Uint32ArrayImpl(ArrayBuffer buffer, int byteOffset, int length) {
+    super(buffer, byteOffset, length * BYTES_PER_ELEMENT);
+  }
+
+  @Override
+  public long get(int index) {
+    long val = arrayBuf.getInt32(checkRange(index, BYTES_PER_ELEMENT), USE_LITTLE_ENDIAN);
+    if (val < 0) {
+      val += 0x100000000L;
+    }
+    return val;
+  }
+
+  @Override
+  public double getAsDouble(int index) {
+    return get(index);
+  }
+
+  @Override
+  public int length() {
+    return byteLength() / BYTES_PER_ELEMENT;
+  }
+
+  @Override
+  public void set(double[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(double[] array, int offset) {
+    int len = array.length;
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array[i]);
+    }
+  }
+
+  @Override
+  public void set(int index, double value) {
+    set(index, (long) value);
+  }
+
+  @Override
+  public void set(int index, long value) {
+    arrayBuf.setInt32(checkRange(index, BYTES_PER_ELEMENT), (int) (value & 0xFFFFFFFF),
+        USE_LITTLE_ENDIAN);
+  }
+
+  @Override
+  public void set(long[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(long[] array, int offset) {
+    int len = array.length;
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array[i]);
+    }
+  }
+
+  @Override
+  public void set(Uint32Array array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(Uint32Array array, int offset) {
+    int len = array.length();
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array.get(i));
+    }
+  }
+
+  @Override
+  public Uint32Array subarray(int begin) {
+    int count = (byteLength() - byteOffset()) / BYTES_PER_ELEMENT;
+    return subarray(begin, count);
+  }
+
+  @Override
+  public Uint32Array subarray(int begin, int end) {
+    int count = (byteLength() - byteOffset()) / BYTES_PER_ELEMENT;
+    if (begin < 0) {
+      begin += count;
+      if (begin < 0) {
+        begin = 0;
+      }
+    } else if (begin > count) {
+      begin = count;
+    }
+    if (end < 0) {
+      end += count;
+      if (end < 0) {
+        end = 0;
+      }
+    } else if (end > count) {
+      end = count;
+    }
+    if (end < begin) {
+      end = begin;
+    }
+    return new Uint32ArrayImpl(arrayBuf, begin * BYTES_PER_ELEMENT, end * BYTES_PER_ELEMENT);
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/server/Uint8ArrayImpl.java b/user/src/com/google/gwt/typedarrays/server/Uint8ArrayImpl.java
new file mode 100644
index 0000000..a04875f
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/server/Uint8ArrayImpl.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.server;
+
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Uint8Array;
+
+/**
+ * Pure Java implementation of {@link Uint8Array}.
+ */
+public class Uint8ArrayImpl extends ArrayBufferViewImpl implements Uint8Array {
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param length
+   */
+  public Uint8ArrayImpl(ArrayBuffer buffer, int byteOffset, int length) {
+    super(buffer, byteOffset, length);
+  }
+
+  @Override
+  public short get(int index) {
+    short val = arrayBuf.getInt8(checkRange(index, BYTES_PER_ELEMENT));
+    if (val < 0) {
+      val += 0x100;
+    }
+    return val;
+  }
+
+  @Override
+  public int length() {
+    return byteLength();
+  }
+
+  @Override
+  public void set(int index, int value) {
+    arrayBuf.setInt8(checkRange(index, BYTES_PER_ELEMENT), (byte) (value & 0xFF));
+  }
+
+  @Override
+  public void set(int[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(int[] array, int offset) {
+    int len = array.length;
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array[i]);
+    }
+  }
+
+  @Override
+  public void set(short[] array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(short[] array, int offset) {
+    int len = array.length;
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array[i]);
+    }
+  }
+
+  @Override
+  public void set(Uint8Array array) {
+    set(array, 0);
+  }
+
+  @Override
+  public void set(Uint8Array array, int offset) {
+    int len = array.length();
+    if (offset + len > length()) {
+      throw new IndexOutOfBoundsException();
+    }
+    for (int i = 0; i < len; ++i) {
+      set(offset++, array.get(i));
+    }
+  }
+
+  @Override
+  public Uint8Array subarray(int begin) {
+    int count = (byteLength() - byteOffset()) / BYTES_PER_ELEMENT;
+    return subarray(begin, count);
+  }
+
+  @Override
+  public Uint8Array subarray(int begin, int end) {
+    int count = (byteLength() - byteOffset()) / BYTES_PER_ELEMENT;
+    if (begin < 0) {
+      begin += count;
+      if (begin < 0) {
+        begin = 0;
+      }
+    } else if (begin > count) {
+      begin = count;
+    }
+    if (end < 0) {
+      end += count;
+      if (end < 0) {
+        end = 0;
+      }
+    } else if (end > count) {
+      end = count;
+    }
+    if (end < begin) {
+      end = begin;
+    }
+    return new Uint8ArrayImpl(arrayBuf, begin * BYTES_PER_ELEMENT, end * BYTES_PER_ELEMENT);
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/server/Uint8ClampedArrayImpl.java b/user/src/com/google/gwt/typedarrays/server/Uint8ClampedArrayImpl.java
new file mode 100644
index 0000000..3372475
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/server/Uint8ClampedArrayImpl.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.server;
+
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Uint8ClampedArray;
+
+/**
+ * Pure Java implementation of {@link Uint8ClampedArray}.
+ */
+public final class Uint8ClampedArrayImpl extends Uint8ArrayImpl implements Uint8ClampedArray {
+
+  /**
+   * @param buffer
+   * @param byteOffset
+   * @param byteLength
+   */
+  public Uint8ClampedArrayImpl(ArrayBuffer buffer, int byteOffset, int byteLength) {
+    super(buffer, byteOffset, byteLength);
+  }
+
+  @Override
+  public void set(int index, int value) {
+    super.set(index, Math.max(0, Math.min(value, 255)));
+  }
+
+  @Override
+  public Uint8ClampedArray subarray(int begin) {
+    int count = byteLength() - byteOffset();
+    return subarray(begin, count);
+  }
+
+  @Override
+  public Uint8ClampedArray subarray(int begin, int end) {
+    int count = byteLength() - byteOffset();
+    if (begin < 0) {
+      begin += count;
+      if (begin < 0) {
+        begin = 0;
+      }
+    } else if (begin > count) {
+      begin = count;
+    }
+    if (end < 0) {
+      end += count;
+      if (end < 0) {
+        end = 0;
+      }
+    } else if (end > count) {
+      end = count;
+    }
+    if (end < begin) {
+      end = begin;
+    }
+    return new Uint8ClampedArrayImpl(buffer(), begin, end);
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/shared/ArrayBuffer.java b/user/src/com/google/gwt/typedarrays/shared/ArrayBuffer.java
new file mode 100644
index 0000000..d83fa09
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/shared/ArrayBuffer.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+/**
+ * A buffer containing an arbitrary sequence of bytes.
+ * 
+ * {@link "http://www.khronos.org/registry/typedarray/specs/latest/#5"}
+ */
+public interface ArrayBuffer {
+
+  /**
+   * The length of the {@link ArrayBuffer} in bytes, which does not change.
+   *
+   * @return non-negative length
+   */
+  int byteLength();
+}
diff --git a/user/src/com/google/gwt/typedarrays/shared/ArrayBufferView.java b/user/src/com/google/gwt/typedarrays/shared/ArrayBufferView.java
new file mode 100644
index 0000000..9b9b1de
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/shared/ArrayBufferView.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+/**
+ * Common information across all types of views of {@link ArrayBuffer}s.
+ * 
+ * {@link "http://www.khronos.org/registry/typedarray/specs/latest/#6"}
+ */
+public interface ArrayBufferView {
+
+  /**
+   * Get the underlying {@link ArrayBuffer}.
+   * 
+   * @return the {@link ArrayBuffer} instance backing this view
+   */
+  ArrayBuffer buffer();
+
+  /**
+   * Get the length of this view in bytes.
+   * 
+   * @return number of bytes in this view
+   */
+  int byteLength();
+
+  /**
+   * Get the offset from the beginning of the underlying {@link ArrayBuffer}.
+   * 
+   * @return 0-based offset from the beginning of {@link #buffer()}
+   */
+  int byteOffset();
+}
diff --git a/user/src/com/google/gwt/typedarrays/shared/DataView.java b/user/src/com/google/gwt/typedarrays/shared/DataView.java
new file mode 100644
index 0000000..a76ba9a
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/shared/DataView.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+/**
+ * A view representing an {@link ArrayBuffer} as heterogeneous values.
+ * 
+ * {@link "http://www.khronos.org/registry/typedarray/specs/latest/#8"}
+ */
+public interface DataView extends ArrayBufferView {
+
+  float getFloat32(int byteOffset);
+
+  float getFloat32(int byteOffset, boolean littleEndian);
+
+  double getFloat64(int byteOffset);
+
+  double getFloat64(int byteOffset, boolean littleEndian);
+
+  short getInt16(int byteOffset);
+
+  short getInt16(int byteOffset, boolean littleEndian);
+
+  int getInt32(int byteOffset);
+
+  int getInt32(int byteOffset, boolean littleEndian);
+
+  byte getInt8(int byteOffset);
+
+  int getUint16(int byteOffset);
+
+  int getUint16(int byteOffset, boolean littleEndian);
+
+  long getUint32(int byteOffset);
+
+  long getUint32(int byteOffset, boolean littleEndian);
+
+  /**
+   * @param byteOffset
+   * @return unsigned 32-bit int as a double
+   */
+  double getUint32AsDouble(int byteOffset);
+
+  /**
+   * @param byteOffset
+   * @param littleEndian
+   * @return unsigned 32-bit int as a double
+   */
+  double getUint32AsDouble(int byteOffset, boolean littleEndian);
+
+  short getUint8(int byteOffset);
+
+  void setFloat32(int byteOffset, float value);
+
+  void setFloat32(int byteOffset, float value, boolean littleEndian);
+
+  void setFloat64(int byteOffset, double value);
+
+  void setFloat64(int byteOffset, double value, boolean littleEndian);
+
+  void setInt16(int byteOffset, int value);
+
+  void setInt16(int byteOffset, int value, boolean littleEndian);
+
+  void setInt32(int byteOffset, int value);
+
+  void setInt32(int byteOffset, int value, boolean littleEndian);
+
+  void setInt8(int byteOffset, int value);
+
+  void setUint16(int byteOffset, int value);
+
+  void setUint16(int byteOffset, int value, boolean littleEndian);
+
+  void setUint32(int byteOffset, long value);
+
+  void setUint32(int byteOffset, long value, boolean littleEndian);
+
+  /**
+   * @param byteOffset
+   * @param value
+   */
+  void setUint32FromDouble(int byteOffset, double value);
+
+  /**
+   * @param byteOffset
+   * @param value
+   * @param littleEndian
+   */
+  void setUint32FromDouble(int byteOffset, double value, boolean littleEndian);
+
+  void setUint8(int byteOffset, int i);
+}
diff --git a/user/src/com/google/gwt/typedarrays/shared/DataViewStream.java b/user/src/com/google/gwt/typedarrays/shared/DataViewStream.java
new file mode 100644
index 0000000..8d5d1b7
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/shared/DataViewStream.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+/**
+ * A stream of heterogeneous values on top of a {@link DataViewStream}.
+ */
+public class DataViewStream {
+  // TODO: add methods to pack/unpack strings in various formats
+
+  private final DataView dataView;
+  private int offset;
+
+  public DataViewStream(DataView dataView) {
+    this.dataView = dataView;
+    offset = 0;
+  }
+
+  public float getFloat32() {
+    return getFloat32(false);
+  }
+
+  public float getFloat32(boolean littleEndian) {
+    float val = dataView.getFloat32(offset, littleEndian);
+    offset += 4;
+    return val;
+  }
+
+  public double getFloat64() {
+    return getFloat64(false);
+  }
+
+  public double getFloat64(boolean littleEndian) {
+    double val = dataView.getFloat64(offset, littleEndian);
+    offset += 8;
+    return val;
+  }
+
+  public short getInt16() {
+    return getInt16(false);
+  }
+
+  public short getInt16(boolean littleEndian) {
+    short val = dataView.getInt16(offset, littleEndian);
+    offset += 2;
+    return val;
+  }
+
+  public int getInt32() {
+    return getInt32(false);
+  }
+
+  public int getInt32(boolean littleEndian) {
+    int val = dataView.getInt32(offset, littleEndian);
+    offset += 4;
+    return val;
+  }
+
+  public byte getInt8() {
+    return dataView.getInt8(offset++);
+  }
+
+  public int getUint16() {
+    return getUint16(false);
+  }
+
+  public int getUint16(boolean littleEndian) {
+    int val = dataView.getUint16(offset, littleEndian);
+    offset += 2;
+    return val;
+  }
+
+  public long getUint32() {
+    return getUint32(false);
+  }
+
+  public long getUint32(boolean littleEndian) {
+    long val = dataView.getUint32(offset, littleEndian);
+    offset += 4;
+    return val;
+  }
+
+  /**
+   * @return unsigned 32-bit int as a double
+   */
+  public double getUint32AsDouble() {
+    return getUint32AsDouble(false);
+  }
+
+  /**
+   * @param littleEndian
+   * @return unsigned 32-bit int as a double
+   */
+  public double getUint32AsDouble(boolean littleEndian) {
+    double val = dataView.getUint32AsDouble(offset, littleEndian);
+    offset += 4;
+    return val;
+  }
+
+  public short getUint8() {
+    return dataView.getUint8(offset++);
+  }
+
+  public int position() {
+    return offset;
+  }
+
+  public void putFloat32(float value) {
+    putFloat32(value, false);
+  }
+
+  public void putFloat32(float value, boolean littleEndian) {
+    dataView.setFloat32(offset, value, littleEndian);
+    offset += 4;
+  }
+
+  public void putFloat64(double value) {
+    putFloat64(value, false);
+  }
+
+  public void putFloat64(double value, boolean littleEndian) {
+    dataView.setFloat64(offset, value, littleEndian);
+    offset += 8;
+  }
+
+  public void putInt16(int value) {
+    putInt16(value, false);
+  }
+
+  public void putInt16(int value, boolean littleEndian) {
+    dataView.setInt16(offset, value, littleEndian);
+    offset += 2;
+  }
+
+  public void putInt32(int value) {
+    putInt32(value, false);
+  }
+
+  public void putInt32(int value, boolean littleEndian) {
+    dataView.setInt32(offset, value, littleEndian);
+    offset += 4;
+  }
+
+  public void putInt8(int value) {
+    dataView.setInt8(offset++, value);
+  }
+
+  public void putUint16(int value) {
+    putUint16(value, false);
+  }
+
+  public void putUint16(int value, boolean littleEndian) {
+    dataView.setUint16(offset, value, littleEndian);
+    offset += 2;
+  }
+
+  public void putUint32(long value) {
+    putUint32(value, false);
+  }
+
+  public void putUint32(long value, boolean littleEndian) {
+    dataView.setUint32(offset, value, littleEndian);
+    offset += 4;
+  }
+
+  /**
+   * @param value
+   */
+  public void putUint32FromDouble(double value) {
+    putUint32FromDouble(value, false);
+  }
+
+  /**
+   * @param value
+   * @param littleEndian
+   */
+  public void putUint32FromDouble(double value, boolean littleEndian) {
+    dataView.setUint32FromDouble(offset, value, littleEndian);
+    offset += 4;
+  }
+
+  public void putUint8(int value) {
+    dataView.setUint8(offset++, value);
+  }
+
+  public void rewind() {
+    offset = 0;
+  }
+
+  public void setPosition(int position) {
+    if (position < 0 || position >= dataView.byteLength()) {
+      throw new IndexOutOfBoundsException();
+    }
+    offset = position;
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/shared/Float32Array.java b/user/src/com/google/gwt/typedarrays/shared/Float32Array.java
new file mode 100644
index 0000000..4f5528d
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/shared/Float32Array.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+/**
+ * A view representing an {@link ArrayBuffer} as 32-bit floats.
+ * 
+ * {@link "http://www.khronos.org/registry/typedarray/specs/latest/#7"}
+ */
+public interface Float32Array extends ArrayBufferView {
+
+  final int BYTES_PER_ELEMENT = 4;
+
+  /**
+   * The length in elements of this view.
+   * 
+   * @return non-negative length
+   */
+  int length();
+
+  /**
+   * Retrieve one element of this view.
+   * 
+   * @param index
+   * @return the requested element
+   */
+  float get(int index);
+
+  /**
+   * Set one element in this view.
+   * 
+   * @param index
+   * @param value
+   */
+  void set(int index, float value);
+
+  /**
+   * Set multiple elements in this view from another view, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(Float32Array array);
+
+  /**
+   * Set multiple elements in this view from another view, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   * @param offset 
+   */
+  void set(Float32Array array, int offset);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(float[] array);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   * @param offset 
+   */
+  void set(float[] array, int offset);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to the end of
+   * this view. These offset is clamped to legal indices into this view, so it
+   * is not an error to specify an invalid index.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index
+   *        from the end of this view
+   * @return a new {@link Float32Array} instance
+   */
+  Float32Array subarray(int begin);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to (but not
+   * including) {@code end} in this view.  These indices are clamped to legal
+   * indices into this view, so it is not an error to specify invalid indices.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @param end offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @return a new {@link Float32Array} instance
+   */
+  Float32Array subarray(int begin, int end);
+}
diff --git a/user/src/com/google/gwt/typedarrays/shared/Float64Array.java b/user/src/com/google/gwt/typedarrays/shared/Float64Array.java
new file mode 100644
index 0000000..0a90d54
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/shared/Float64Array.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+/**
+ * A view representing an {@link ArrayBuffer} as 32-bit floats.
+ * 
+ * {@link "http://www.khronos.org/registry/typedarray/specs/latest/#7"}
+ */
+public interface Float64Array extends ArrayBufferView {
+
+  final int BYTES_PER_ELEMENT = 8;
+
+  /**
+   * The length in elements of this view.
+   * 
+   * @return non-negative length
+   */
+  int length();
+
+  /**
+   * Retrieve one element of this view.
+   * 
+   * @param index
+   * @return the requested element
+   */
+  double get(int index);
+
+  /**
+   * Set one element in this view.
+   * 
+   * @param index
+   * @param value
+   */
+  void set(int index, double value);
+
+  /**
+   * Set multiple elements in this view from another view, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(Float64Array array);
+
+  /**
+   * Set multiple elements in this view from another view, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   */
+  void set(Float64Array array, int offset);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(double[] array);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   */
+  void set(double[] array, int offset);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to the end of
+   * this view. These offset is clamped to legal indices into this view, so it
+   * is not an error to specify an invalid index.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index
+   *        from the end of this view
+   * @return a new {@link Float64Array} instance
+   */
+  Float64Array subarray(int begin);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to (but not
+   * including) {@code end} in this view.  These indices are clamped to legal
+   * indices into this view, so it is not an error to specify invalid indices.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @param end offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @return a new {@link Float64Array} instance
+   */
+  Float64Array subarray(int begin, int end);
+}
diff --git a/user/src/com/google/gwt/typedarrays/shared/Int16Array.java b/user/src/com/google/gwt/typedarrays/shared/Int16Array.java
new file mode 100644
index 0000000..81a6f33
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/shared/Int16Array.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+/**
+ * A view representing an {@link ArrayBuffer} as 16-bit signed integers.  Storing
+ * out-of-range values are mapped to valid values by taking the bottom 16 bits of
+ * the value.
+ * 
+ * {@link "http://www.khronos.org/registry/typedarray/specs/latest/#7"}
+ */
+public interface Int16Array extends ArrayBufferView {
+
+  final int BYTES_PER_ELEMENT = 2;
+
+  /**
+   * The length in elements of this view.
+   * 
+   * @return non-negative length
+   */
+  int length();
+
+  /**
+   * Retrieve one element of this view.
+   * 
+   * @param index
+   * @return the requested element
+   */
+  short get(int index);
+
+  /**
+   * Set one element in this view.
+   * 
+   * @param index
+   * @param value
+   */
+  void set(int index, int value);
+
+  /**
+   * Set multiple elements in this view from another view, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(Int16Array array);
+
+  /**
+   * Set multiple elements in this view from another view, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   */
+  void set(Int16Array array, int offset);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(short[] array);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   */
+  void set(short[] array, int offset);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(int[] array);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   */
+  void set(int[] array, int offset);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to the end of
+   * this view. These offset is clamped to legal indices into this view, so it
+   * is not an error to specify an invalid index.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index
+   *        from the end of this view
+   * @return a new {@link Int16Array} instance
+   */
+  Int16Array subarray(int begin);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to (but not
+   * including) {@code end} in this view.  These indices are clamped to legal
+   * indices into this view, so it is not an error to specify invalid indices.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @param end offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @return a new {@link Int16Array} instance
+   */
+  Int16Array subarray(int begin, int end);
+}
diff --git a/user/src/com/google/gwt/typedarrays/shared/Int32Array.java b/user/src/com/google/gwt/typedarrays/shared/Int32Array.java
new file mode 100644
index 0000000..59d6650
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/shared/Int32Array.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+/**
+ * A view representing an {@link ArrayBuffer} as 32-bit signed integers.  Storing
+ * out-of-range values are mapped to valid values by taking the bottom 32 bits of
+ * the value.
+ * 
+ * {@link "http://www.khronos.org/registry/typedarray/specs/latest/#7"}
+ */
+public interface Int32Array extends ArrayBufferView {
+
+  final int BYTES_PER_ELEMENT = 4;
+
+  /**
+   * The length in elements of this view.
+   * 
+   * @return non-negative length
+   */
+  int length();
+
+  /**
+   * Retrieve one element of this view.
+   * 
+   * @param index
+   * @return the requested element
+   */
+  int get(int index);
+
+  /**
+   * Set one element in this view.
+   * 
+   * @param index
+   * @param value
+   */
+  void set(int index, int value);
+
+  /**
+   * Set multiple elements in this view from another view, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(Int32Array array);
+
+  /**
+   * Set multiple elements in this view from another view, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   */
+  void set(Int32Array array, int offset);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(int[] array);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   */
+  void set(int[] array, int offset);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to the end of
+   * this view. These offset is clamped to legal indices into this view, so it
+   * is not an error to specify an invalid index.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index
+   *        from the end of this view
+   * @return a new {@link Int32Array} instance
+   */
+  Int32Array subarray(int begin);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to (but not
+   * including) {@code end} in this view.  These indices are clamped to legal
+   * indices into this view, so it is not an error to specify invalid indices.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @param end offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @return a new {@link Int32Array} instance
+   */
+  Int32Array subarray(int begin, int end);
+}
diff --git a/user/src/com/google/gwt/typedarrays/shared/Int8Array.java b/user/src/com/google/gwt/typedarrays/shared/Int8Array.java
new file mode 100644
index 0000000..9ad55fa
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/shared/Int8Array.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+/**
+ * A view representing an {@link ArrayBuffer} as 8-bit signed integers.  Storing
+ * out-of-range values are mapped to valid values by taking the bottom 8 bits of
+ * the value.
+ * 
+ * {@link "http://www.khronos.org/registry/typedarray/specs/latest/#7"}
+ */
+public interface Int8Array extends ArrayBufferView {
+
+  final int BYTES_PER_ELEMENT = 1;
+
+  /**
+   * The length in elements of this view.
+   * 
+   * @return non-negative length
+   */
+  int length();
+
+  /**
+   * Retrieve one element of this view.
+   * 
+   * @param index
+   * @return the requested element
+   */
+  byte get(int index);
+
+  /**
+   * Set one element in this view.
+   * 
+   * @param index
+   * @param value
+   */
+  void set(int index, int value);
+
+  /**
+   * Set multiple elements in this view from another view, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(Int8Array array);
+
+  /**
+   * Set multiple elements in this view from another view, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   */
+  void set(Int8Array array, int offset);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(byte[] array);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   */
+  void set(byte[] array, int offset);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(int[] array);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   */
+  void set(int[] array, int offset);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to the end of
+   * this view. These offset is clamped to legal indices into this view, so it
+   * is not an error to specify an invalid index.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index
+   *        from the end of this view
+   * @return a new {@link Int8Array} instance
+   */
+  Int8Array subarray(int begin);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to (but not
+   * including) {@code end} in this view.  These indices are clamped to legal
+   * indices into this view, so it is not an error to specify invalid indices.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @param end offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @return a new {@link Int8Array} instance
+   */
+  Int8Array subarray(int begin, int end);
+}
diff --git a/user/src/com/google/gwt/typedarrays/shared/TypedArrays.java b/user/src/com/google/gwt/typedarrays/shared/TypedArrays.java
new file mode 100644
index 0000000..0d8a285
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/shared/TypedArrays.java
@@ -0,0 +1,810 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+/**
+ * Factory class for various typed arrays.  Behavior of all other methods is
+ * undefined if {@link #isSupported()} returns false.
+ * <p>
+ * In client code, the various types are implemented by JavaScriptObjects,
+ * so you cannot reliable use instanceof checks on any of the returned
+ * implementations.
+ */
+public class TypedArrays {
+
+  /**
+   * Base class of implementations for creating various typed array structures.
+   * <p>
+   * <b>*** NOT A PUBLIC API ***</b>
+   */
+  public abstract static class Impl {
+
+    /**
+     * Get the number of elements in a number of bytes, throwing an exception
+     * if it isn't an integral number.
+     * 
+     * @param byteLength
+     * @param elemLength length of each element in bytes
+     * @return count of elements
+     * @throws IllegalArgumentException if {@code byteLength} isn't an integral
+     *     multiple of {@code elemLength}
+     */
+    protected static int getElementCount(int byteLength, int elemLength) {
+      int count =  byteLength / elemLength;
+      if (count * elemLength != byteLength) {
+        throw new IllegalArgumentException();
+      }
+      return count;
+    }
+
+    public abstract ArrayBuffer createArrayBuffer(int length);
+
+    public DataView createDataView(ArrayBuffer buffer) {
+      return createDataView(buffer, 0, buffer.byteLength());
+    }
+
+    public DataView createDataView(ArrayBuffer buffer, int offset) {
+      return createDataView(buffer, offset, buffer.byteLength() - offset);
+    }
+
+    public abstract DataView createDataView(ArrayBuffer buffer, int byteOffset, int byteLength);
+
+    public Float32Array createFloat32Array(ArrayBuffer buffer) {
+      return createFloat32Array(buffer, 0, getElementCount(buffer.byteLength(),
+          Float32Array.BYTES_PER_ELEMENT));
+    }
+
+    public Float32Array createFloat32Array(ArrayBuffer buffer, int byteOffset) {
+      return createFloat32Array(buffer, byteOffset, getElementCount(
+          buffer.byteLength() - byteOffset, Float32Array.BYTES_PER_ELEMENT));
+    }
+
+    public abstract Float32Array createFloat32Array(ArrayBuffer buffer, int byteOffset, int length);
+
+    public Float32Array createFloat32Array(float[] array) {
+      Float32Array result = createFloat32Array(array.length);
+      result.set(array);
+      return result;
+    }
+
+    public Float32Array createFloat32Array(int length) {
+      return createFloat32Array(createArrayBuffer(length * Float32Array.BYTES_PER_ELEMENT));
+    }
+
+    public Float64Array createFloat64Array(ArrayBuffer buffer) {
+      return createFloat64Array(buffer, 0, getElementCount(buffer.byteLength(),
+          Float64Array.BYTES_PER_ELEMENT));
+    }
+
+    public Float64Array createFloat64Array(ArrayBuffer buffer, int byteOffset) {
+      return createFloat64Array(buffer, byteOffset, getElementCount(
+          buffer.byteLength() - byteOffset, Float64Array.BYTES_PER_ELEMENT));
+    }
+
+    public abstract Float64Array createFloat64Array(ArrayBuffer buffer, int byteOffset, int length);
+
+    public Float64Array createFloat64Array(double[] array) {
+      Float64Array result = createFloat64Array(array.length);
+      result.set(array);
+      return result;
+    }
+
+    public Float64Array createFloat64Array(int length) {
+      return createFloat64Array(createArrayBuffer(length * Float64Array.BYTES_PER_ELEMENT));
+    }
+
+    public Int16Array createInt16Array(ArrayBuffer buffer) {
+      return createInt16Array(buffer, 0, getElementCount(buffer.byteLength(),
+          Int16Array.BYTES_PER_ELEMENT));
+    }
+
+    public Int16Array createInt16Array(ArrayBuffer buffer, int byteOffset) {
+      return createInt16Array(buffer, byteOffset, getElementCount(
+          buffer.byteLength() - byteOffset, Int16Array.BYTES_PER_ELEMENT));
+    }
+
+    public abstract Int16Array createInt16Array(ArrayBuffer buffer, int byteOffset, int length);
+
+    public Int16Array createInt16Array(int length) {
+      return createInt16Array(createArrayBuffer(length * Int16Array.BYTES_PER_ELEMENT));
+    }
+
+    public Int16Array createInt16Array(short[] array) {
+      Int16Array result = createInt16Array(array.length);
+      result.set(array);
+      return result;
+    }
+
+    public Int32Array createInt32Array(ArrayBuffer buffer) {
+      return createInt32Array(buffer, 0, getElementCount(buffer.byteLength(),
+          Int32Array.BYTES_PER_ELEMENT));
+    }
+
+    public Int32Array createInt32Array(ArrayBuffer buffer, int byteOffset) {
+      return createInt32Array(buffer, byteOffset, getElementCount(
+          buffer.byteLength() - byteOffset, Int32Array.BYTES_PER_ELEMENT));
+    }
+
+    public abstract Int32Array createInt32Array(ArrayBuffer buffer, int byteOffset, int length);
+
+    public Int32Array createInt32Array(int length) {
+      return createInt32Array(createArrayBuffer(length * Int32Array.BYTES_PER_ELEMENT));
+    }
+
+    public Int32Array createInt32Array(int[] array) {
+      Int32Array result = createInt32Array(array.length);
+      result.set(array);
+      return result;
+    }
+
+    public Int8Array createInt8Array(ArrayBuffer buffer) {
+      return createInt8Array(buffer, 0, buffer.byteLength());
+    }
+
+    public Int8Array createInt8Array(ArrayBuffer buffer, int byteOffset) {
+      return createInt8Array(buffer, byteOffset, buffer.byteLength() - byteOffset);
+    }
+
+    public abstract Int8Array createInt8Array(ArrayBuffer buffer, int byteOffset, int length);
+
+    public Int8Array createInt8Array(byte[] array) {
+      Int8Array result = createInt8Array(array.length);
+      result.set(array);
+      return result;
+    }
+
+    public Int8Array createInt8Array(int length) {
+      return createInt8Array(createArrayBuffer(length));
+    }
+
+    public Uint16Array createUint16Array(ArrayBuffer buffer) {
+      return createUint16Array(buffer, 0, getElementCount(buffer.byteLength(),
+          Uint16Array.BYTES_PER_ELEMENT));
+    }
+
+    public Uint16Array createUint16Array(ArrayBuffer buffer, int byteOffset) {
+      return createUint16Array(buffer, byteOffset, getElementCount(
+          buffer.byteLength() - byteOffset, Uint16Array.BYTES_PER_ELEMENT));
+    }
+
+    public abstract Uint16Array createUint16Array(ArrayBuffer buffer, int byteOffset, int length);
+
+    public Uint16Array createUint16Array(int length) {
+      return createUint16Array(createArrayBuffer(length * Uint16Array.BYTES_PER_ELEMENT));
+    }
+
+    public Uint16Array createUint16Array(int[] array) {
+      Uint16Array result = createUint16Array(array.length);
+      result.set(array);
+      return result;
+    }
+
+    public Uint32Array createUint32Array(ArrayBuffer buffer) {
+      return createUint32Array(buffer, 0, getElementCount(buffer.byteLength(),
+          Uint32Array.BYTES_PER_ELEMENT));
+    }
+
+    public Uint32Array createUint32Array(ArrayBuffer buffer, int byteOffset) {
+      return createUint32Array(buffer, byteOffset, getElementCount(
+          buffer.byteLength() - byteOffset, Uint32Array.BYTES_PER_ELEMENT));
+    }
+
+    public abstract Uint32Array createUint32Array(ArrayBuffer buffer, int byteOffset, int length);
+
+    public Uint32Array createUint32Array(double[] array) {
+      Uint32Array result = createUint32Array(array.length);
+      result.set(array);
+      return result;
+    }
+
+    public Uint32Array createUint32Array(int length) {
+      return createUint32Array(createArrayBuffer(length * Uint32Array.BYTES_PER_ELEMENT));
+    }
+
+    public Uint32Array createUint32Array(long[] array) {
+      Uint32Array result = createUint32Array(array.length);
+      result.set(array);
+      return result;
+    }
+
+    public Uint8Array createUint8Array(ArrayBuffer buffer) {
+      return createUint8Array(buffer, 0, buffer.byteLength());
+    }
+
+    public Uint8Array createUint8Array(ArrayBuffer buffer, int byteOffset) {
+      return createUint8Array(buffer, byteOffset, buffer.byteLength() - byteOffset);
+    }
+
+    public abstract Uint8Array createUint8Array(ArrayBuffer buffer, int byteOffset, int length);
+
+    public Uint8Array createUint8Array(int length) {
+      return createUint8Array(createArrayBuffer(length));
+    }
+
+    public Uint8Array createUint8Array(short[] array) {
+      Uint8Array result = createUint8Array(array.length);
+      result.set(array);
+      return result;
+    }
+
+    public Uint8ClampedArray createUint8ClampedArray(ArrayBuffer buffer) {
+      return createUint8ClampedArray(buffer, 0, buffer.byteLength());
+    }
+
+    public Uint8ClampedArray createUint8ClampedArray(ArrayBuffer buffer, int byteOffset) {
+      return createUint8ClampedArray(buffer, byteOffset, buffer.byteLength() - byteOffset);
+    }
+
+    public abstract Uint8ClampedArray createUint8ClampedArray(ArrayBuffer buffer, int byteOffset,
+        int length);
+
+    public Uint8ClampedArray createUint8ClampedArray(int length) {
+      return createUint8ClampedArray(createArrayBuffer(length));
+    }
+
+    public Uint8ClampedArray createUint8ClampedArray(short[] array) {
+      Uint8ClampedArray result = createUint8ClampedArray(array.length);
+      result.set(array);
+      return result;
+    }
+
+    /**
+     * Check if the current environment might possibly support typed arrays.
+     * <p>
+     * The default implementation always returns true, and this is intended to
+     * be a static check based on deffered-bound parameters.
+     * 
+     * @return true if the current environment might possibly
+     *     support typed arrays
+     */
+    protected boolean mightBeSupported() {
+      return true;
+    }
+
+    /**
+     * Check if the current environment actually does support typed arrays
+     * (including emulation).  There is no partial support, so if true is
+     * returned, there must be acceptable implementations for all of the
+     * {@code createXXX} methods. 
+     * 
+     * @return true if the current environment actually does support typed
+     *     arrays
+     */
+    protected boolean runtimeSupportCheck() {
+      return false;
+    }
+  }
+
+  /**
+   * This class exists to keep clinit calls from littering callsites when compiled
+   * to JS.
+   */
+  private static class Instance {
+    protected static final Impl impl = TypedArraysFactory.createImpl();
+  }
+
+  /**
+   * Create a new {@link ArrayBuffer} of {@code length} bytes.
+   * 
+   * @param length length of buffer in bytes
+   * @return an {@link ArrayBuffer} instance
+   */
+  public static ArrayBuffer createArrayBuffer(int length) {
+    return Instance.impl.createArrayBuffer(length);
+  }
+
+  /**
+   * Create a new {@link DataView} instance on an {@link ArrayBuffer}.
+   * 
+   * @param buffer {@link ArrayBuffer}
+   * @return {@link DataView} instance
+   */
+  public static DataView createDataView(ArrayBuffer buffer) {
+    return Instance.impl.createDataView(buffer);
+  }
+
+  /**
+   * Create a new {@link DataView} instance on an {@link ArrayBuffer}, starting
+   * at an offset of {@code byteOffset}.
+   * 
+   * @param buffer {@link ArrayBuffer}
+   * @param byteOffset offset into buffer
+   * @return {@link DataView} instance
+   */
+  public static DataView createDataView(ArrayBuffer buffer, int byteOffset) {
+    return Instance.impl.createDataView(buffer, byteOffset);
+  }
+
+  /**
+   * Create a new {@link DataView} instance on an {@link ArrayBuffer}, starting
+   * at an offset of {@code byteOffset} and continuing for {@code length}
+   * bytes.
+   * 
+   * @param buffer {@link ArrayBuffer}
+   * @param byteOffset offset into buffer
+   * @param byteLength length of view in bytes
+   * @return {@link DataView} instance
+   */
+  public static DataView createDataView(ArrayBuffer buffer, int byteOffset, int byteLength) {
+    return Instance.impl.createDataView(buffer, byteOffset, byteLength);
+  }
+
+  /**
+   * Create a {@link Float32Array} instance on {@code buffer}, starting at
+   * starting at the beginning of the buffer and continuing to the end (which
+   * must be an integral number of elements).
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @return an {@link Float32Array} instance
+   */
+  public static Float32Array createFloat32Array(ArrayBuffer buffer) {
+    return Instance.impl.createFloat32Array(buffer);
+  }
+
+  /**
+   * Create a {@link Float32Array} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing to the end of the buffer
+   * (which must be an integral number of elements).
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @return an {@link Float32Array} instance
+   */
+  public static Float32Array createFloat32Array(ArrayBuffer buffer, int byteOffset) {
+    return Instance.impl.createFloat32Array(buffer, byteOffset);
+  }
+
+  /**
+   * Create a {@link Float32Array} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing for {@code length}
+   * elements.
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @param length number of elements in the resulting array
+   * @return an {@link Float32Array} instance
+   */
+  public static Float32Array createFloat32Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return Instance.impl.createFloat32Array(buffer, byteOffset, length);
+  }
+
+  /**
+   * Create a {@link Float32Array} instance of {@code length} elements, backed
+   * by a new {@link ArrayBuffer}.
+   * 
+   * @param length size of array
+   * @return a {@link Float32Array} instance
+   */
+  public static Float32Array createFloat32Array(int length) {
+    return Instance.impl.createFloat32Array(length);
+  }
+
+  /**
+   * Create a {@link Float64Array} instance on {@code buffer}, starting at
+   * starting at the beginning of the buffer and continuing to the end (which
+   * must be an integral number of elements).
+   * <p>
+   * <b>Note that Safari does not currently support Float64 Arrays!</b>
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @return an {@link Float64Array} instance
+   */
+  public static Float64Array createFloat64Array(ArrayBuffer buffer) {
+    return Instance.impl.createFloat64Array(buffer);
+  }
+
+  /**
+   * Create a {@link Float64Array} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing to the end of the buffer
+   * (which must be an integral number of elements).
+   * <p>
+   * <b>Note that Safari does not currently support Float64 Arrays!</b>
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @return an {@link Float64Array} instance
+   */
+  public static Float64Array createFloat64Array(ArrayBuffer buffer, int byteOffset) {
+    return Instance.impl.createFloat64Array(buffer, byteOffset);
+  }
+
+  /**
+   * Create a {@link Float64Array} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing for {@code length}
+   * elements.
+   * <p>
+   * <b>Note that Safari does not currently support Float64 Arrays!</b>
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @param length number of elements in the resulting array
+   * @return an {@link Float64Array} instance
+   */
+  public static Float64Array createFloat64Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return Instance.impl.createFloat64Array(buffer, byteOffset, length);
+  }
+
+  /**
+   * Create a {@link Float64Array} instance of {@code length} elements, backed
+   * by a new {@link ArrayBuffer}.
+   * <p>
+   * <b>Note that Safari does not currently support Float64 Arrays!</b>
+   * 
+   * @param length size of array
+   * @return a {@link Float64Array} instance
+   */
+  public static Float64Array createFloat64Array(int length) {
+    return Instance.impl.createFloat64Array(length);
+  }
+
+  /**
+   * Create a {@link Int16Array} instance on {@code buffer}, starting at
+   * starting at the beginning of the buffer and continuing to the end (which
+   * must be an integral number of elements).
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @return an {@link Int16Array} instance
+   */
+  public static Int16Array createInt16Array(ArrayBuffer buffer) {
+    return Instance.impl.createInt16Array(buffer);
+  }
+
+  /**
+   * Create a {@link Int16Array} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing to the end of the buffer
+   * (which must be an integral number of elements).
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @return an {@link Int16Array} instance
+   */
+  public static Int16Array createInt16Array(ArrayBuffer buffer, int byteOffset) {
+    return Instance.impl.createInt16Array(buffer, byteOffset);
+  }
+
+  /**
+   * Create a {@link Int16Array} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing for {@code length}
+   * elements.
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @param length number of elements in the resulting array
+   * @return an {@link Int16Array} instance
+   */
+  public static Int16Array createInt16Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return Instance.impl.createInt16Array(buffer, byteOffset, length);
+  }
+
+  /**
+   * Create a {@link Int16Array} instance of {@code length} elements, backed
+   * by a new {@link ArrayBuffer}.
+   * 
+   * @param length size of array
+   * @return a {@link Int16Array} instance
+   */
+  public static Int16Array createInt16Array(int length) {
+    return Instance.impl.createInt16Array(length);
+  }
+
+  /**
+   * Create a {@link Int32Array} instance on {@code buffer}, starting at
+   * starting at the beginning of the buffer and continuing to the end (which
+   * must be an integral number of elements).
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @return an {@link Int32Array} instance
+   */
+  public static Int32Array createInt32Array(ArrayBuffer buffer) {
+    return Instance.impl.createInt32Array(buffer);
+  }
+
+  /**
+   * Create a {@link Int32Array} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing to the end of the buffer
+   * (which must be an integral number of elements).
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @return an {@link Int32Array} instance
+   */
+  public static Int32Array createInt32Array(ArrayBuffer buffer, int byteOffset) {
+    return Instance.impl.createInt32Array(buffer, byteOffset);
+  }
+
+  /**
+   * Create a {@link Int32Array} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing for {@code length}
+   * elements.
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @param length number of elements in the resulting array
+   * @return an {@link Int32Array} instance
+   */
+  public static Int32Array createInt32Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return Instance.impl.createInt32Array(buffer, byteOffset, length);
+  }
+
+  /**
+   * Create a {@link Int32Array} instance of {@code length} elements, backed
+   * by a new {@link ArrayBuffer}.
+   * 
+   * @param length size of array
+   * @return a {@link Int32Array} instance
+   */
+  public static Int32Array createInt32Array(int length) {
+    return Instance.impl.createInt32Array(length);
+  }
+
+  /**
+   * Create a {@link Int8Array} instance on {@code buffer}, starting at
+   * starting at the beginning of the buffer and continuing to the end.
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @return an {@link Int8Array} instance
+   */
+  public static Int8Array createInt8Array(ArrayBuffer buffer) {
+    return Instance.impl.createInt8Array(buffer);
+  }
+
+  /**
+   * Create a {@link Int8Array} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing to the end of the buffer
+   * (which must be an integral number of elements).
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @return an {@link Int8Array} instance
+   */
+  public static Int8Array createInt8Array(ArrayBuffer buffer, int byteOffset) {
+    return Instance.impl.createInt8Array(buffer, byteOffset);
+  }
+
+  /**
+   * Create a {@link Int8Array} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing for {@code length}
+   * elements.
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @param length number of elements in the resulting array
+   * @return an {@link Int8Array} instance
+   */
+  public static Int8Array createInt8Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return Instance.impl.createInt8Array(buffer, byteOffset, length);
+  }
+
+  /**
+   * Create a {@link Int8Array} instance of {@code length} elements, backed
+   * by a new {@link ArrayBuffer}.
+   * 
+   * @param length size of array
+   * @return a {@link Int8Array} instance
+   */
+  public static Int8Array createInt8Array(int length) {
+    return Instance.impl.createInt8Array(length);
+  }
+
+  /**
+   * Create a {@link Uint16Array} instance on {@code buffer}, starting at
+   * starting at the beginning of the buffer and continuing to the end (which
+   * must be an integral number of elements).
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @return an {@link Uint16Array} instance
+   */
+  public static Uint16Array createUint16Array(ArrayBuffer buffer) {
+    return Instance.impl.createUint16Array(buffer);
+  }
+
+  /**
+   * Create a {@link Uint16Array} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing to the end of the buffer
+   * (which must be an integral number of elements).
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @return an {@link Uint16Array} instance
+   */
+  public static Uint16Array createUint16Array(ArrayBuffer buffer, int byteOffset) {
+    return Instance.impl.createUint16Array(buffer, byteOffset);
+  }
+
+  /**
+   * Create a {@link Uint16Array} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing for {@code length}
+   * elements.
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @param length number of elements in the resulting array
+   * @return an {@link Uint16Array} instance
+   */
+  public static Uint16Array createUint16Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return Instance.impl.createUint16Array(buffer, byteOffset, length);
+  }
+
+  /**
+   * Create a {@link Uint16Array} instance of {@code length} elements, backed
+   * by a new {@link ArrayBuffer}.
+   * 
+   * @param length size of array
+   * @return a {@link Uint16Array} instance
+   */
+  public static Uint16Array createUint16Array(int length) {
+    return Instance.impl.createUint16Array(length);
+  }
+
+  /**
+   * Create a {@link Uint32Array} instance on {@code buffer}, starting at
+   * starting at the beginning of the buffer and continuing to the end (which
+   * must be an integral number of elements).
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @return an {@link Uint32Array} instance
+   */
+  public static Uint32Array createUint32Array(ArrayBuffer buffer) {
+    return Instance.impl.createUint32Array(buffer);
+  }
+
+  /**
+   * Create a {@link Uint32Array} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing to the end of the buffer
+   * (which must be an integral number of elements).
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @return an {@link Uint32Array} instance
+   */
+  public static Uint32Array createUint32Array(ArrayBuffer buffer, int byteOffset) {
+    return Instance.impl.createUint32Array(buffer, byteOffset);
+  }
+
+  /**
+   * Create a {@link Uint32Array} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing for {@code length}
+   * elements.
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @param length number of elements in the resulting array
+   * @return an {@link Uint32Array} instance
+   */
+  public static Uint32Array createUint32Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return Instance.impl.createUint32Array(buffer, byteOffset, length);
+  }
+
+  /**
+   * Create a {@link Uint32Array} instance of {@code length} elements, backed
+   * by a new {@link ArrayBuffer}.
+   * 
+   * @param length size of array
+   * @return a {@link Uint32Array} instance
+   */
+  public static Uint32Array createUint32Array(int length) {
+    return Instance.impl.createUint32Array(length);
+  }
+
+  /**
+   * Create a {@link Uint8Array} instance on {@code buffer}, starting at
+   * starting at the beginning of the buffer and continuing to the end (which
+   * must be an integral number of elements).
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @return an {@link Uint8Array} instance
+   */
+  public static Uint8Array createUint8Array(ArrayBuffer buffer) {
+    return Instance.impl.createUint8Array(buffer);
+  }
+
+  /**
+   * Create a {@link Uint8Array} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing to the end of the buffer.
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @return an {@link Uint8Array} instance
+   */
+  public static Uint8Array createUint8Array(ArrayBuffer buffer, int byteOffset) {
+    return Instance.impl.createUint8Array(buffer, byteOffset);
+  }
+
+  /**
+   * Create a {@link Uint8Array} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing for {@code length}
+   * elements.
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @param length number of elements in the resulting array
+   * @return an {@link Uint8Array} instance
+   */
+  public static Uint8Array createUint8Array(ArrayBuffer buffer, int byteOffset, int length) {
+    return Instance.impl.createUint8Array(buffer, byteOffset, length);
+  }
+
+  /**
+   * Create a {@link Uint8Array} instance of {@code length} elements, backed
+   * by a new {@link ArrayBuffer}.
+   * 
+   * @param length size of array
+   * @return a {@link Uint8Array} instance
+   */
+  public static Uint8Array createUint8Array(int length) {
+    return Instance.impl.createUint8Array(length);
+  }
+
+  /**
+   * Create a {@link Uint8ClampedArray} instance on {@code buffer}, starting at
+   * starting at the beginning of the buffer and continuing to the end.
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @return an {@link Uint8ClampedArray} instance
+   */
+  public static Uint8ClampedArray createUint8ClampedArray(ArrayBuffer buffer) {
+    return Instance.impl.createUint8ClampedArray(buffer, 0, buffer.byteLength());
+  }
+
+  /**
+   * Create a {@link Uint8ClampedArray} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing to the end of the buffer.
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @return an {@link Uint8ClampedArray} instance
+   */
+  public static Uint8ClampedArray createUint8ClampedArray(ArrayBuffer buffer, int byteOffset) {
+    return Instance.impl.createUint8ClampedArray(buffer, byteOffset);
+  }
+
+  /**
+   * Create a {@link Uint8ClampedArray} instance on {@code buffer}, starting at
+   * {@code byteOffset} into the buffer, continuing for {@code length}
+   * elements.
+   * 
+   * @param buffer underlying {@link ArrayBuffer}
+   * @param byteOffset byte offset from the start of {@code buffer}
+   * @param length number of elements in the resulting array
+   * @return an {@link Uint8ClampedArray} instance
+   */
+  public static Uint8ClampedArray createUint8ClampedArray(ArrayBuffer buffer,
+      int byteOffset, int length) {
+    return Instance.impl.createUint8ClampedArray(buffer, byteOffset, length);
+  }
+
+  /**
+   * Create a {@link Uint8ClampedArray} instance of {@code length} elements, backed
+   * by a new {@link ArrayBuffer}.
+   * 
+   * @param length size of array
+   * @return a {@link Uint8ClampedArray} instance
+   */
+  public static Uint8ClampedArray createUint8ClampedArray(int length) {
+    return Instance.impl.createUint8ClampedArray(length);
+  }
+
+  /**
+   * Check if the current environment supports typed arrays.  Behavior of the
+   * various {@code createXXX} methods is undefined if this method returns
+   * {@code false}, but will typically throw some exception.
+   * 
+   * @return true if typed arrays are support.
+   */
+  public static boolean isSupported() {
+    return Instance.impl.mightBeSupported() && Instance.impl.runtimeSupportCheck();
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/shared/TypedArraysFactory.java b/user/src/com/google/gwt/typedarrays/shared/TypedArraysFactory.java
new file mode 100644
index 0000000..7ea1ae3
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/shared/TypedArraysFactory.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+import com.google.gwt.typedarrays.server.JavaImpl;
+
+/**
+ * Factory for creating a {@link TypedArrays} implementation.
+ * <p>
+ * This is the pure Java version.
+ */
+class TypedArraysFactory {
+
+  static TypedArrays.Impl createImpl() {
+    return new JavaImpl();
+  }
+}
diff --git a/user/src/com/google/gwt/typedarrays/shared/Uint16Array.java b/user/src/com/google/gwt/typedarrays/shared/Uint16Array.java
new file mode 100644
index 0000000..a6d2ab3
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/shared/Uint16Array.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+/**
+ * A view representing an {@link ArrayBuffer} as 16-bit unsigned integers.  Storing
+ * out-of-range values are mapped to valid values by taking the bottom 16 bits of
+ * the value.
+ * 
+ * {@link "http://www.khronos.org/registry/typedarray/specs/latest/#7"}
+ */
+public interface Uint16Array extends ArrayBufferView {
+
+  final int BYTES_PER_ELEMENT = 2;
+
+  /**
+   * The length in elements of this view.
+   * 
+   * @return non-negative length
+   */
+  int length();
+
+  /**
+   * Retrieve one element of this view.
+   * 
+   * @param index
+   * @return the requested element
+   */
+  int get(int index);
+
+  /**
+   * Set one element in this view.
+   * 
+   * @param index
+   * @param value
+   */
+  void set(int index, int value);
+
+  /**
+   * Set multiple elements in this view from another view, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(Uint16Array array);
+
+  /**
+   * Set multiple elements in this view from another view, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   */
+  void set(Uint16Array array, int offset);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(int[] array);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   */
+  void set(int[] array, int offset);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to the end of
+   * this view. These offset is clamped to legal indices into this view, so it
+   * is not an error to specify an invalid index.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index
+   *        from the end of this view
+   * @return a new {@link Uint16Array} instance
+   */
+  Uint16Array subarray(int begin);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to (but not
+   * including) {@code end} in this view.  These indices are clamped to legal
+   * indices into this view, so it is not an error to specify invalid indices.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @param end offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @return a new {@link Uint16Array} instance
+   */
+  Uint16Array subarray(int begin, int end);
+}
diff --git a/user/src/com/google/gwt/typedarrays/shared/Uint32Array.java b/user/src/com/google/gwt/typedarrays/shared/Uint32Array.java
new file mode 100644
index 0000000..69593a7
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/shared/Uint32Array.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+/**
+ * A view representing an {@link ArrayBuffer} as 32-bit unsigned integers.  Storing
+ * out-of-range values are mapped to valid values by taking the bottom 32 bits of
+ * the value.
+ * 
+ * {@link "http://www.khronos.org/registry/typedarray/specs/latest/#7"}
+ */
+public interface Uint32Array extends ArrayBufferView {
+
+  final int BYTES_PER_ELEMENT = 4;
+
+  /**
+   * The length in elements of this view.
+   * 
+   * @return non-negative length
+   */
+  int length();
+
+  /**
+   * Retrieve one element of this view.
+   * 
+   * @param index
+   * @return the requested element
+   */
+  long get(int index);
+
+  /**
+   * Retrieve one element of this view.
+   * 
+   * @param index
+   * @return the requested element as a double
+   */
+  double getAsDouble(int index);
+
+  /**
+   * Set one element in this view.
+   * 
+   * @param index
+   * @param value
+   */
+  void set(int index, long value);
+
+  /**
+   * Set one element in this view.
+   * 
+   * @param index
+   * @param value
+   */
+  void set(int index, double value);
+
+  /**
+   * Set multiple elements in this view from another view, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(Uint32Array array);
+
+  /**
+   * Set multiple elements in this view from another view, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   */
+  void set(Uint32Array array, int offset);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(long[] array);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   */
+  void set(long[] array, int offset);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(double[] array);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   */
+  void set(double[] array, int offset);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to the end of
+   * this view. These offset is clamped to legal indices into this view, so it
+   * is not an error to specify an invalid index.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index
+   *        from the end of this view
+   * @return a new {@link Uint32Array} instance
+   */
+  Uint32Array subarray(int begin);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to (but not
+   * including) {@code end} in this view.  These indices are clamped to legal
+   * indices into this view, so it is not an error to specify invalid indices.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @param end offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @return a new {@link Uint32Array} instance
+   */
+  Uint32Array subarray(int begin, int end);
+}
diff --git a/user/src/com/google/gwt/typedarrays/shared/Uint8Array.java b/user/src/com/google/gwt/typedarrays/shared/Uint8Array.java
new file mode 100644
index 0000000..1688b7d
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/shared/Uint8Array.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+/**
+ * A view representing an {@link ArrayBuffer} as 8-bit unsigned integers.  Storing
+ * out-of-range values are mapped to valid values by taking the bottom 8 bits of
+ * the value as an unassigned.
+ * 
+ * {@link "http://www.khronos.org/registry/typedarray/specs/latest/#7"}
+ */
+public interface Uint8Array extends ArrayBufferView {
+
+  final int BYTES_PER_ELEMENT = 1;
+
+  /**
+   * The length in elements of this view.
+   * 
+   * @return non-negative length
+   */
+  int length();
+
+  /**
+   * Retrieve one element of this view.
+   * 
+   * @param index
+   * @return the requested element, 0-255
+   */
+  short get(int index);
+
+  /**
+   * Set one element in this view.
+   * 
+   * @param index
+   * @param value
+   */
+  void set(int index, int value);
+
+  /**
+   * Set multiple elements in this view from another view, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(Uint8Array array);
+
+  /**
+   * Set multiple elements in this view from another view, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   * @param offset 
+   */
+  void set(Uint8Array array, int offset);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(int[] array);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   * @param offset 
+   */
+  void set(int[] array, int offset);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at 0.
+   * 
+   * @param array
+   */
+  void set(short[] array);
+
+  /**
+   * Set multiple elements in this view from an array, storing starting at the
+   * requested offset.
+   * 
+   * @param array
+   * @param offset 
+   */
+  void set(short[] array, int offset);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to the end of
+   * this view. These offset is clamped to legal indices into this view, so it
+   * is not an error to specify an invalid index.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index
+   *        from the end of this view
+   * @return a new {@link Uint8Array} instance
+   */
+  Uint8Array subarray(int begin);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to (but not
+   * including) {@code end} in this view.  These indices are clamped to legal
+   * indices into this view, so it is not an error to specify invalid indices.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @param end offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @return a new {@link Uint8Array} instance
+   */
+  Uint8Array subarray(int begin, int end);
+}
diff --git a/user/src/com/google/gwt/typedarrays/shared/Uint8ClampedArray.java b/user/src/com/google/gwt/typedarrays/shared/Uint8ClampedArray.java
new file mode 100644
index 0000000..dca41c8
--- /dev/null
+++ b/user/src/com/google/gwt/typedarrays/shared/Uint8ClampedArray.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+/**
+ * A view representing an {@link ArrayBuffer} as 8-bit unsigned integers.  Storing
+ * out-of-range values are mapped to valid values by clamping to the range 0-255.
+ * 
+ * {@link "http://www.khronos.org/registry/typedarray/specs/latest/#7"}
+ */
+public interface Uint8ClampedArray extends Uint8Array {
+
+  /**
+   * Create a new view from the same array, from {@code offset} to the end of
+   * this view. These offset is clamped to legal indices into this view, so it
+   * is not an error to specify an invalid index.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index
+   *        from the end of this view
+   * @return a new {@link Uint8ClampedArray} instance
+   */
+  @Override
+  Uint8ClampedArray subarray(int begin);
+
+  /**
+   * Create a new view from the same array, from {@code offset} to (but not
+   * including) {@code end} in this view.  These indices are clamped to legal
+   * indices into this view, so it is not an error to specify invalid indices.
+   * 
+   * @param begin offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @param end offset into this view if non-negative; if negative, an index from
+   *     the end of this view
+   * @return a new {@link Uint8ClampedArray} instance
+   */
+  @Override
+  Uint8ClampedArray subarray(int begin, int end);
+}
diff --git a/user/src/com/google/gwt/user/UserAgent.gwt.xml b/user/src/com/google/gwt/user/UserAgent.gwt.xml
index 197b0a6..e521f13 100644
--- a/user/src/com/google/gwt/user/UserAgent.gwt.xml
+++ b/user/src/com/google/gwt/user/UserAgent.gwt.xml
@@ -1,5 +1,5 @@
 <!--                                                                        -->
-<!-- Copyright 2007 Google Inc.                                             -->
+<!-- Copyright 2012 Google Inc.                                             -->
 <!-- Licensed under the Apache License, Version 2.0 (the "License"); you    -->
 <!-- may not use this file except in compliance with the License. You may   -->
 <!-- may obtain a copy of the License at                                    -->
@@ -15,33 +15,8 @@
 <!-- Defines the user.agent property and its provider function.             -->
 <!--                                                                        -->
 <!-- This module is typically inherited via com.google.gwt.user.User        -->
+<!-- New code should inherit c.g.g.useragent.UserAgent instead.             -->
 <!--                                                                        -->
 <module>
-
-  <!-- Browser-sensitive code should use the 'user.agent' property -->
-  <define-property name="user.agent" values="ie6" />
-  <extend-property name="user.agent" values="ie8" />
-  <extend-property name="user.agent" values="gecko1_8" />
-  <extend-property name="user.agent" values="safari" />
-  <extend-property name="user.agent" values="opera" />
-  <extend-property name="user.agent" values="ie9" fallback-value="ie8" />
-  <property-provider name="user.agent" generator="com.google.gwt.user.rebind.UserAgentPropertyGenerator"/>
-
-  <!-- Set to false to avoid runtime warnings for mismatched runtime and -->
-  <!-- compile time user.agent values -->
-  <define-configuration-property name="user.agent.runtimeWarning"
-    is-multi-valued="false" />
-  <set-configuration-property name="user.agent.runtimeWarning" value="true"/>
-
-  <!-- Asserts that the compile time user.agent value matches the runtime -->
-  <!-- user.agent value -->
-  <entry-point class="com.google.gwt.user.client.UserAgentAsserter" />
-
-  <generate-with class="com.google.gwt.user.rebind.UserAgentGenerator">
-    <when-type-assignable class="com.google.gwt.user.client.UserAgentAsserter.UserAgentProperty" />
-  </generate-with>
-
-  <!-- Deferred binding to optimize JRE classes based on user agent. -->
-  <inherits name="com.google.gwt.emul.EmulationWithUserAgent"/>
-  <inherits name="com.google.gwt.core.CoreWithUserAgent"/>
+  <inherits name="com.google.gwt.useragent.UserAgent"/>
 </module>
diff --git a/user/src/com/google/gwt/useragent/UserAgent.gwt.xml b/user/src/com/google/gwt/useragent/UserAgent.gwt.xml
new file mode 100644
index 0000000..16a65ec
--- /dev/null
+++ b/user/src/com/google/gwt/useragent/UserAgent.gwt.xml
@@ -0,0 +1,47 @@
+<!--                                                                        -->
+<!-- Copyright 2007 Google Inc.                                             -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you    -->
+<!-- may not use this file except in compliance with the License. You may   -->
+<!-- may obtain a copy of the License at                                    -->
+<!--                                                                        -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0                             -->
+<!--                                                                        -->
+<!-- Unless required by applicable law or agreed to in writing, software    -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS,      -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        -->
+<!-- implied. License for the specific language governing permissions and   -->
+<!-- limitations under the License.                                         -->
+
+<!-- Defines the user.agent property and its provider function.             -->
+<!--                                                                        -->
+<!-- This module is typically inherited via com.google.gwt.user.User        -->
+<!--                                                                        -->
+<module>
+
+  <!-- Browser-sensitive code should use the 'user.agent' property -->
+  <define-property name="user.agent" values="ie6" />
+  <extend-property name="user.agent" values="ie8" />
+  <extend-property name="user.agent" values="gecko1_8" />
+  <extend-property name="user.agent" values="safari" />
+  <extend-property name="user.agent" values="opera" />
+  <extend-property name="user.agent" values="ie9" fallback-value="ie8" />
+  <property-provider name="user.agent" generator="com.google.gwt.useragent.rebind.UserAgentPropertyGenerator"/>
+
+  <!-- Set to false to avoid runtime warnings for mismatched runtime and -->
+  <!-- compile time user.agent values -->
+  <define-configuration-property name="user.agent.runtimeWarning"
+    is-multi-valued="false" />
+  <set-configuration-property name="user.agent.runtimeWarning" value="true"/>
+
+  <!-- Asserts that the compile time user.agent value matches the runtime -->
+  <!-- user.agent value -->
+  <entry-point class="com.google.gwt.useragent.client.UserAgentAsserter" />
+
+  <generate-with class="com.google.gwt.useragent.rebind.UserAgentGenerator">
+    <when-type-assignable class="com.google.gwt.useragent.client.UserAgentAsserter.UserAgentProperty" />
+  </generate-with>
+
+  <!-- Deferred binding to optimize JRE classes based on user agent. -->
+  <inherits name="com.google.gwt.emul.EmulationWithUserAgent"/>
+  <inherits name="com.google.gwt.core.CoreWithUserAgent"/>
+</module>
diff --git a/user/src/com/google/gwt/user/client/UserAgentAsserter.java b/user/src/com/google/gwt/useragent/client/UserAgentAsserter.java
similarity index 97%
rename from user/src/com/google/gwt/user/client/UserAgentAsserter.java
rename to user/src/com/google/gwt/useragent/client/UserAgentAsserter.java
index aadfd88..9ac749a 100644
--- a/user/src/com/google/gwt/user/client/UserAgentAsserter.java
+++ b/user/src/com/google/gwt/useragent/client/UserAgentAsserter.java
@@ -14,7 +14,7 @@
  * the License.
  */
 
-package com.google.gwt.user.client;
+package com.google.gwt.useragent.client;
 
 import com.google.gwt.core.client.EntryPoint;
 import com.google.gwt.core.client.GWT;
@@ -40,6 +40,7 @@
     String getRuntimeValue();
   }
 
+  @Override
   public void onModuleLoad() {
     UserAgentProperty impl = GWT.create(UserAgentProperty.class);
     if (!impl.getUserAgentRuntimeWarning()) {
diff --git a/user/src/com/google/gwt/user/rebind/UserAgentGenerator.java b/user/src/com/google/gwt/useragent/rebind/UserAgentGenerator.java
similarity index 94%
rename from user/src/com/google/gwt/user/rebind/UserAgentGenerator.java
rename to user/src/com/google/gwt/useragent/rebind/UserAgentGenerator.java
index b5bb6fc..fb777b9 100644
--- a/user/src/com/google/gwt/user/rebind/UserAgentGenerator.java
+++ b/user/src/com/google/gwt/useragent/rebind/UserAgentGenerator.java
@@ -14,7 +14,7 @@
  * the License.
  */
 
-package com.google.gwt.user.rebind;
+package com.google.gwt.useragent.rebind;
 
 import com.google.gwt.core.ext.BadPropertyValueException;
 import com.google.gwt.core.ext.ConfigurationProperty;
@@ -27,11 +27,13 @@
 import com.google.gwt.core.ext.typeinfo.JClassType;
 import com.google.gwt.core.ext.typeinfo.NotFoundException;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
+import com.google.gwt.user.rebind.SourceWriter;
 
 import java.io.PrintWriter;
 
 /**
- * Generator for {@link com.google.gwt.user.client.UserAgentAsserter}.
+ * Generator for {@link com.google.gwt.useragent.client.UserAgentAsserter}.
  */
 public class UserAgentGenerator extends Generator {
   static final String PROPERTY_USER_AGENT = "user.agent";
diff --git a/user/src/com/google/gwt/user/rebind/UserAgentPropertyGenerator.java b/user/src/com/google/gwt/useragent/rebind/UserAgentPropertyGenerator.java
similarity index 95%
rename from user/src/com/google/gwt/user/rebind/UserAgentPropertyGenerator.java
rename to user/src/com/google/gwt/useragent/rebind/UserAgentPropertyGenerator.java
index d0d9104..0a44fd5 100644
--- a/user/src/com/google/gwt/user/rebind/UserAgentPropertyGenerator.java
+++ b/user/src/com/google/gwt/useragent/rebind/UserAgentPropertyGenerator.java
@@ -14,11 +14,13 @@
  * the License.
  */
 
-package com.google.gwt.user.rebind;
+package com.google.gwt.useragent.rebind;
 
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.linker.ConfigurationProperty;
 import com.google.gwt.core.ext.linker.PropertyProviderGenerator;
+import com.google.gwt.user.rebind.SourceWriter;
+import com.google.gwt.user.rebind.StringSourceWriter;
 
 import java.util.Arrays;
 import java.util.List;
@@ -33,7 +35,7 @@
   /**
    * List of valid user agent selection property values, which helps ensure that
    * UserAgent.gwt.xml stays in sync with the
-   * {@link #writeUserAgentPropertyJavaScript(SourceWriter)} method body of this
+   * {@link #writeUserAgentPropertyJavaScript(SourceWriter,SortedSet)} method body of this
    * class.
    */
   private static final List<String> VALID_VALUES = Arrays.asList(new String[]{
@@ -142,6 +144,7 @@
     body.println("return 'unknown';");
   }
 
+  @Override
   public String generate(TreeLogger logger, SortedSet<String> possibleValues,
       String fallback, SortedSet<ConfigurationProperty> configProperties) {
     for (String value : possibleValues) {
diff --git a/user/src/com/google/gwt/user/rebind/UserAgentPropertyGeneratorPredicate.java b/user/src/com/google/gwt/useragent/rebind/UserAgentPropertyGeneratorPredicate.java
similarity index 94%
rename from user/src/com/google/gwt/user/rebind/UserAgentPropertyGeneratorPredicate.java
rename to user/src/com/google/gwt/useragent/rebind/UserAgentPropertyGeneratorPredicate.java
index 66cb73d..9cd0353 100644
--- a/user/src/com/google/gwt/user/rebind/UserAgentPropertyGeneratorPredicate.java
+++ b/user/src/com/google/gwt/useragent/rebind/UserAgentPropertyGeneratorPredicate.java
@@ -14,7 +14,9 @@
  * the License.
  */
 
-package com.google.gwt.user.rebind;
+package com.google.gwt.useragent.rebind;
+
+import com.google.gwt.user.rebind.StringSourceWriter;
 
 /**
  * Represents a predicate expressed in Javascript
diff --git a/user/src/com/google/gwt/xhr/XMLHttpRequest.gwt.xml b/user/src/com/google/gwt/xhr/XMLHttpRequest.gwt.xml
index 214dc42..645b124 100644
--- a/user/src/com/google/gwt/xhr/XMLHttpRequest.gwt.xml
+++ b/user/src/com/google/gwt/xhr/XMLHttpRequest.gwt.xml
@@ -18,5 +18,6 @@
 <!-- package must inherit this module.                                      -->
 <!--                                                                        -->
 <module>
-	<inherits name="com.google.gwt.core.Core"/>
+  <inherits name="com.google.gwt.core.Core"/>
+  <inherits name="com.google.gwt.typedarrays.TypedArrays"/>
 </module>
diff --git a/user/src/com/google/gwt/xhr/client/XMLHttpRequest.java b/user/src/com/google/gwt/xhr/client/XMLHttpRequest.java
index c1a1d15..925c33a 100644
--- a/user/src/com/google/gwt/xhr/client/XMLHttpRequest.java
+++ b/user/src/com/google/gwt/xhr/client/XMLHttpRequest.java
@@ -16,6 +16,7 @@
 package com.google.gwt.xhr.client;
 
 import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
 
 /**
  * The native XMLHttpRequest object. Most applications should use the higher-
@@ -27,6 +28,40 @@
  */
 public class XMLHttpRequest extends JavaScriptObject {
 
+  /**
+   * The type of response expected from the XHR.
+   */
+  public enum ResponseType {
+    /**
+     * The default response type -- use {@link XMLHttpRequest#getResponseText()}
+     * for the return value.
+     */
+    Default(""),
+
+    /**
+     * The default response type -- use
+     * {@link XMLHttpRequest#getResponseArrayBuffer()} for the return value.
+     * This value may only be used if
+     * {@link com.google.gwt.typedarrays.shared.TypedArrays#isSupported()}
+     * returns true.
+     */
+    ArrayBuffer("arraybuffer");
+
+    // not implemented yet
+    /*
+    Blob("blob"),
+    
+    Document("document"),
+    
+    Text("text");
+    */
+
+    protected final String responseTypeString;
+
+    private ResponseType(String responseTypeString) {
+      this.responseTypeString = responseTypeString;
+    }
+  }
   /*
    * NOTE: Testing discovered that for some bizarre reason, on Mozilla, the
    * JavaScript <code>XmlHttpRequest.onreadystatechange</code> handler
@@ -81,19 +116,44 @@
    * 
    * @return the created object
    */
-  public static native XMLHttpRequest create() /*-{
+  public static XMLHttpRequest create() {
+    return create(ResponseType.Default);
+  }
+
+  /**
+   * Creates an XMLHttpRequest object.
+   * 
+   * @param responseType the type of response desired.  See {@link ResponseType}
+   *     for limitations on using the different values
+   * @return the created object
+   */
+  public static XMLHttpRequest create(ResponseType responseType) {
+    return create(responseType.responseTypeString);
+  }
+
+  /**
+   * Creates an XMLHttpRequest object.
+   * 
+   * @return the created object
+   */
+  private static native XMLHttpRequest create(String responseType) /*-{
     // Don't check window.XMLHttpRequest, because it can
     // cause cross-site problems on IE8 if window's URL
     // is javascript:'' .
+    var xhr;
     if ($wnd.XMLHttpRequest) {
-      return new $wnd.XMLHttpRequest();
+      xhr = new $wnd.XMLHttpRequest();
     } else {
       try {
-        return new $wnd.ActiveXObject('MSXML2.XMLHTTP.3.0');
+        xhr = new $wnd.ActiveXObject('MSXML2.XMLHTTP.3.0');
       } catch (e) {
-        return new $wnd.ActiveXObject("Microsoft.XMLHTTP");
+        xhr = new $wnd.ActiveXObject("Microsoft.XMLHTTP");
       }
     }
+    if (xhr && responseType) {
+      xhr.responsetype = responseType;
+    }
+    return xhr;
   }-*/;
 
   protected XMLHttpRequest() {
@@ -151,6 +211,16 @@
   }-*/;
 
   /**
+   * Get the response as an {@link ArrayBuffer}.
+   * 
+   * @return an {@link ArrayBuffer} containing the response, or null if the
+   *     request is in progress or failed
+   */
+  public final native ArrayBuffer getResponseArrayBuffer() /*-{
+    return this.response;
+  }-*/;
+
+  /**
    * Gets an HTTP response header.
    * <p>
    * See <a href="http://www.w3.org/TR/XMLHttpRequest/#getresponseheader"
diff --git a/user/super/com/google/gwt/typedarrays/super/com/google/gwt/typedarrays/shared/TypedArraysFactory.java b/user/super/com/google/gwt/typedarrays/super/com/google/gwt/typedarrays/shared/TypedArraysFactory.java
new file mode 100644
index 0000000..80162df
--- /dev/null
+++ b/user/super/com/google/gwt/typedarrays/super/com/google/gwt/typedarrays/shared/TypedArraysFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.typedarrays.client.NativeImpl;
+
+/**
+ * Factory for creating a {@link TypedArrays} implementation.
+ * <p>
+ * This is the client version.
+ */
+class TypedArraysFactory {
+
+  static TypedArrays.Impl createImpl() {
+    return GWT.create(NativeImpl.class);
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/TypedArraysSuite.java b/user/test/com/google/gwt/typedarrays/TypedArraysSuite.java
new file mode 100644
index 0000000..93f91ad
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/TypedArraysSuite.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays;
+
+import com.google.gwt.junit.tools.GWTTestSuite;
+import com.google.gwt.typedarrays.client.ClientSupportTest;
+import com.google.gwt.typedarrays.client.GwtDataViewTest;
+import com.google.gwt.typedarrays.client.GwtFloat32ArrayTest;
+import com.google.gwt.typedarrays.client.GwtFloat64ArrayTest;
+import com.google.gwt.typedarrays.client.GwtInt16ArrayTest;
+import com.google.gwt.typedarrays.client.GwtInt32ArrayTest;
+import com.google.gwt.typedarrays.client.GwtInt8ArrayTest;
+import com.google.gwt.typedarrays.client.GwtUint16ArrayTest;
+import com.google.gwt.typedarrays.client.GwtUint32ArrayTest;
+import com.google.gwt.typedarrays.client.GwtUint8ArrayTest;
+import com.google.gwt.typedarrays.client.GwtUint8ClampedArrayTest;
+import com.google.gwt.typedarrays.client.StringArrayBufferTest;
+import com.google.gwt.typedarrays.shared.DataViewTest;
+import com.google.gwt.typedarrays.shared.Float32ArrayTest;
+import com.google.gwt.typedarrays.shared.Float64ArrayTest;
+import com.google.gwt.typedarrays.shared.Int16ArrayTest;
+import com.google.gwt.typedarrays.shared.Int32ArrayTest;
+import com.google.gwt.typedarrays.shared.Int8ArrayTest;
+import com.google.gwt.typedarrays.shared.Uint16ArrayTest;
+import com.google.gwt.typedarrays.shared.Uint32ArrayTest;
+import com.google.gwt.typedarrays.shared.Uint8ArrayTest;
+import com.google.gwt.typedarrays.shared.Uint8ClampedArrayTest;
+
+import junit.framework.Test;
+
+/**
+ * All TypedArray tests.
+ */
+public class TypedArraysSuite {
+  public static Test suite() {
+    GWTTestSuite suite = new GWTTestSuite("All TypedArray tests");
+
+    // $JUnit-BEGIN$
+    // Client tests
+    suite.addTestSuite(ClientSupportTest.class);
+    suite.addTestSuite(GwtDataViewTest.class);
+    suite.addTestSuite(GwtFloat32ArrayTest.class);
+    suite.addTestSuite(GwtFloat64ArrayTest.class);
+    suite.addTestSuite(GwtInt16ArrayTest.class);
+    suite.addTestSuite(GwtInt32ArrayTest.class);
+    suite.addTestSuite(GwtInt8ArrayTest.class);
+    suite.addTestSuite(GwtUint16ArrayTest.class);
+    suite.addTestSuite(GwtUint32ArrayTest.class);
+    suite.addTestSuite(GwtUint8ArrayTest.class);
+    suite.addTestSuite(GwtUint8ClampedArrayTest.class);
+    suite.addTestSuite(StringArrayBufferTest.class);
+
+    // Pure Java tests
+    suite.addTestSuite(DataViewTest.class);
+    suite.addTestSuite(Float32ArrayTest.class);
+    suite.addTestSuite(Float64ArrayTest.class);
+    suite.addTestSuite(Int16ArrayTest.class);
+    suite.addTestSuite(Int32ArrayTest.class);
+    suite.addTestSuite(Int8ArrayTest.class);
+    suite.addTestSuite(Uint16ArrayTest.class);
+    suite.addTestSuite(Uint32ArrayTest.class);
+    suite.addTestSuite(Uint8ArrayTest.class);
+    suite.addTestSuite(Uint8ClampedArrayTest.class);
+
+    // $JUnit-END$
+
+    return suite;
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/TypedArraysTest.gwt.xml b/user/test/com/google/gwt/typedarrays/TypedArraysTest.gwt.xml
new file mode 100644
index 0000000..cd3e8b3
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/TypedArraysTest.gwt.xml
@@ -0,0 +1,19 @@
+<!--                                                                        -->
+<!-- Copyright 2012 Google Inc.                                             -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you    -->
+<!-- may not use this file except in compliance with the License. You may   -->
+<!-- may obtain a copy of the License at                                    -->
+<!--                                                                        -->
+<!-- http://www.apache.org/licenses/LICENSE-2.0                             -->
+<!--                                                                        -->
+<!-- Unless required by applicable law or agreed to in writing, software    -->
+<!-- distributed under the License is distributed on an "AS IS" BASIS,      -->
+<!-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        -->
+<!-- implied. License for the specific language governing permissions and   -->
+<!-- limitations under the License.                                         -->
+
+<module>
+  <inherits name="com.google.gwt.typedarrays.TypedArrays"/>
+  <source path="client" />
+  <source path="shared" />
+ </module>
diff --git a/user/test/com/google/gwt/typedarrays/client/ClientSupportTest.java b/user/test/com/google/gwt/typedarrays/client/ClientSupportTest.java
new file mode 100644
index 0000000..8e879ef
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/client/ClientSupportTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.typedarrays.shared.TypedArrays;
+
+/**
+ * Test that client-side code has support on the user agents
+ * where it is expected.
+ */
+public class ClientSupportTest extends GWTTestCase {
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.typedarrays.TypedArraysTest";
+  }
+
+  public void testSupported() {
+    boolean isSupported = TypedArrays.isSupported();
+    String ua = getUserAgent();
+    if (ua.contains("msie")) {
+      assertEquals("IE10+ should support typed arrays",
+          getIeDocumentMode() >= 10, isSupported);
+      return;
+    }
+    if (ua.contains("firefox/")) {
+      int idx = ua.indexOf("firefox/") + 8;
+      int endIdx = idx;
+      int len = ua.length();
+      while (endIdx < len && Character.isDigit(ua.charAt(endIdx))) {
+        endIdx++;
+      }
+      int majorVers = Integer.parseInt(ua.substring(idx, endIdx), 10);
+      // FF4+ should support typed arrays
+      assertEquals("FF" + majorVers, majorVers >= 4, isSupported);
+      return;
+    }
+    if (ua.contains("opera")) {
+      // which versions support typed arrays?
+      assertTrue(isSupported);
+      return;
+    }
+    if (ua.contains("webkit")) {
+      // which versions support typed arrays?
+      assertTrue(isSupported);
+      return;
+    }
+    assertFalse("Unknown browser (" + ua + ") assumed not to support typed arrays",
+        isSupported);
+  }
+
+  private static native String getUserAgent() /*-{
+    return navigator.userAgent.toLowerCase();
+  }-*/;
+
+  private static native int getIeDocumentMode() /*-{
+    return $doc.documentMode;
+  }-*/;
+}
diff --git a/user/test/com/google/gwt/typedarrays/client/GwtDataViewTest.java b/user/test/com/google/gwt/typedarrays/client/GwtDataViewTest.java
new file mode 100644
index 0000000..11fca91
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/client/GwtDataViewTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.typedarrays.shared.DataViewTest;
+
+
+/**
+ * Test client {@link com.google.gwt.typedarrays.shared.DataView} implementations.
+ */
+public class GwtDataViewTest extends DataViewTest {
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.typedarrays.TypedArraysTest";
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/client/GwtFloat32ArrayTest.java b/user/test/com/google/gwt/typedarrays/client/GwtFloat32ArrayTest.java
new file mode 100644
index 0000000..06134dd
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/client/GwtFloat32ArrayTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JsArrayNumber;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Float32Array;
+import com.google.gwt.typedarrays.shared.Float32ArrayTest;
+import com.google.gwt.typedarrays.shared.TypedArrays;
+
+/**
+ * Test client {@link Float32Array} implementations.
+ */
+public class GwtFloat32ArrayTest extends Float32ArrayTest {
+
+  private static native JsArrayNumber getJsoArray() /*-{
+    return [ 1, Number.NEGATIVE_INFINITY, Number.NaN, 3.4028235e+38 ];
+  }-*/;
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.typedarrays.TypedArraysTest";
+  }
+
+  public void testCreateJsArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    JsArrayNumber src = getJsoArray();
+    Float32Array array = JsUtils.createFloat32Array(src);
+    validateArrayContents(array, 0);
+  }
+
+  public void testSetJsArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(24);
+    Float32Array array = TypedArrays.createFloat32Array(buf);
+    setFromJsArray(array, 0);
+    validateArrayContents(array, 0);
+
+    buf = TypedArrays.createArrayBuffer(24);
+    array = TypedArrays.createFloat32Array(buf);
+    setFromJsArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  /**
+   * Initialize from a JSO rather than a Java array
+   */
+  protected void setFromJsArray(Float32Array array, int offset) {
+    JsUtils.set(array, getJsoArray(), offset);
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/client/GwtFloat64ArrayTest.java b/user/test/com/google/gwt/typedarrays/client/GwtFloat64ArrayTest.java
new file mode 100644
index 0000000..17fe09e
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/client/GwtFloat64ArrayTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JsArrayNumber;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Float64Array;
+import com.google.gwt.typedarrays.shared.Float64ArrayTest;
+import com.google.gwt.typedarrays.shared.TypedArrays;
+
+/**
+ * Test client {@link Float64Array} implementations.
+ */
+public class GwtFloat64ArrayTest extends Float64ArrayTest {
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.typedarrays.TypedArraysTest";
+  }
+
+  public void testCreateJsArray() {
+    if (!isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    JsArrayNumber src = getJsoArray();
+    Float64Array array = JsUtils.createFloat64Array(src);
+    validateArrayContents(array, 0);
+  }
+
+  public void testSetJsArray() {
+    if (!isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(48);
+    Float64Array array = TypedArrays.createFloat64Array(buf);
+    setFromJsArray(array, 0);
+    validateArrayContents(array, 0);
+
+    buf = TypedArrays.createArrayBuffer(48);
+    array = TypedArrays.createFloat64Array(buf);
+    setFromJsArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  @Override
+  protected boolean isSupported() {
+    // Safari doesn't currently support Float64Array
+    return super.isSupported() && !isSafari();
+  }
+
+  /**
+   * Initialize from a JSO rather than a Java array
+   */
+  protected void setFromJsArray(Float64Array array, int offset) {
+    JsUtils.set(array, getJsoArray(), offset);
+  }
+
+  private static native JsArrayNumber getJsoArray() /*-{
+    return [ 1, Number.NEGATIVE_INFINITY, Number.NaN, Number.MAX_VALUE ];
+  }-*/;
+
+  private static native boolean isSafari() /*-{
+    var ua = navigator.userAgent.toLowerCase();
+    return ua.indexOf('safari/') != -1 && ua.indexOf('chrome/') == -1;
+  }-*/;
+}
diff --git a/user/test/com/google/gwt/typedarrays/client/GwtInt16ArrayTest.java b/user/test/com/google/gwt/typedarrays/client/GwtInt16ArrayTest.java
new file mode 100644
index 0000000..e104fa1
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/client/GwtInt16ArrayTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JsArrayInteger;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Int16Array;
+import com.google.gwt.typedarrays.shared.Int16ArrayTest;
+import com.google.gwt.typedarrays.shared.TypedArrays;
+
+/**
+ * Test client {@link Int16Array} implementations.
+ */
+public class GwtInt16ArrayTest extends Int16ArrayTest {
+
+  private static native JsArrayInteger getJsoArray() /*-{
+    return [ 1, 2, 65536, -1 ];
+  }-*/;
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.typedarrays.TypedArraysTest";
+  }
+
+  public void testCreateJsArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    JsArrayInteger src = getJsoArray();
+    Int16Array array = JsUtils.createInt16Array(src);
+    validateArrayContents(array, 0);
+  }
+
+  public void testSetJsArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(12);
+    Int16Array array = TypedArrays.createInt16Array(buf);
+    setFromJsArray(array, 0);
+    validateArrayContents(array, 0);
+
+    buf = TypedArrays.createArrayBuffer(12);
+    array = TypedArrays.createInt16Array(buf);
+    setFromJsArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  /**
+   * Initialize from a JSO rather than a Java array
+   */
+  protected void setFromJsArray(Int16Array array, int offset) {
+    JsUtils.set(array, getJsoArray(), offset);
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/client/GwtInt32ArrayTest.java b/user/test/com/google/gwt/typedarrays/client/GwtInt32ArrayTest.java
new file mode 100644
index 0000000..609da50
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/client/GwtInt32ArrayTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JsArrayInteger;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Int32Array;
+import com.google.gwt.typedarrays.shared.Int32ArrayTest;
+import com.google.gwt.typedarrays.shared.TypedArrays;
+
+/**
+ * Test client {@link Int32Array} implementations.
+ */
+public class GwtInt32ArrayTest extends Int32ArrayTest {
+
+  private static native JsArrayInteger getJsoArray() /*-{
+    return [ 1, 2, 65536, -1 ];
+  }-*/;
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.typedarrays.TypedArraysTest";
+  }
+
+  public void testCreateJsArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    JsArrayInteger src = getJsoArray();
+    Int32Array array = JsUtils.createInt32Array(src);
+    validateArrayContents(array, 0);
+  }
+
+  public void testSetJsArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(24);
+    Int32Array array = TypedArrays.createInt32Array(buf);
+    setFromJsArray(array, 0);
+    validateArrayContents(array, 0);
+
+    buf = TypedArrays.createArrayBuffer(24);
+    array = TypedArrays.createInt32Array(buf);
+    setFromJsArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  /**
+   * Initialize from a JSO rather than a Java array
+   */
+  protected void setFromJsArray(Int32Array array, int offset) {
+    JsUtils.set(array, getJsoArray(), offset);
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/client/GwtInt8ArrayTest.java b/user/test/com/google/gwt/typedarrays/client/GwtInt8ArrayTest.java
new file mode 100644
index 0000000..964a672
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/client/GwtInt8ArrayTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JsArrayInteger;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Int8Array;
+import com.google.gwt.typedarrays.shared.Int8ArrayTest;
+import com.google.gwt.typedarrays.shared.TypedArrays;
+
+/**
+ * Test client {@link Int8Array} implementations.
+ */
+public class GwtInt8ArrayTest extends Int8ArrayTest {
+
+  private static native JsArrayInteger getJsoArray() /*-{
+    return [ 1, 2, 256, -1 ];
+  }-*/;
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.typedarrays.TypedArraysTest";
+  }
+
+  public void testCreateJsArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    JsArrayInteger src = getJsoArray();
+    Int8Array array = JsUtils.createInt8Array(src);
+    validateArrayContents(array, 0);
+  }
+
+  public void testSetJsArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(12);
+    Int8Array array = TypedArrays.createInt8Array(buf);
+    setFromJsArray(array, 0);
+    validateArrayContents(array, 0);
+
+    buf = TypedArrays.createArrayBuffer(12);
+    array = TypedArrays.createInt8Array(buf);
+    setFromJsArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  /**
+   * Initialize from a JSO rather than a Java array
+   */
+  protected void setFromJsArray(Int8Array array, int offset) {
+    JsUtils.set(array, getJsoArray(), offset);
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/client/GwtUint16ArrayTest.java b/user/test/com/google/gwt/typedarrays/client/GwtUint16ArrayTest.java
new file mode 100644
index 0000000..1c83293
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/client/GwtUint16ArrayTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JsArrayInteger;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.TypedArrays;
+import com.google.gwt.typedarrays.shared.Uint16Array;
+import com.google.gwt.typedarrays.shared.Uint16ArrayTest;
+
+/**
+ * Test client {@link Uint16Array} implementations.
+ */
+public class GwtUint16ArrayTest extends Uint16ArrayTest {
+
+  private static native JsArrayInteger getJsoArray() /*-{
+    return [ 1, 2, 65536, -1 ];
+  }-*/;
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.typedarrays.TypedArraysTest";
+  }
+
+  public void testCreateJsArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    JsArrayInteger src = getJsoArray();
+    Uint16Array array = JsUtils.createUint16Array(src);
+    validateArrayContents(array, 0);
+  }
+
+  public void testSetJsArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(12);
+    Uint16Array array = TypedArrays.createUint16Array(buf);
+    setFromJsArray(array, 0);
+    validateArrayContents(array, 0);
+
+    buf = TypedArrays.createArrayBuffer(12);
+    array = TypedArrays.createUint16Array(buf);
+    setFromJsArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  /**
+   * Initialize from a JSO rather than a Java array
+   */
+  protected void setFromJsArray(Uint16Array array, int offset) {
+    JsUtils.set(array, getJsoArray(), offset);
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/client/GwtUint32ArrayTest.java b/user/test/com/google/gwt/typedarrays/client/GwtUint32ArrayTest.java
new file mode 100644
index 0000000..43ecdf0
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/client/GwtUint32ArrayTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JsArrayNumber;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.TypedArrays;
+import com.google.gwt.typedarrays.shared.Uint32Array;
+import com.google.gwt.typedarrays.shared.Uint32ArrayTest;
+
+/**
+ * Test client {@link Uint32Array} implementations.
+ */
+public class GwtUint32ArrayTest extends Uint32ArrayTest {
+
+  private static native JsArrayNumber getJsoArray() /*-{
+    return [ 1, 2, 65536, -1 ];
+  }-*/;
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.typedarrays.TypedArraysTest";
+  }
+
+  public void testCreateJsArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    JsArrayNumber src = getJsoArray();
+    Uint32Array array = JsUtils.createUint32Array(src);
+    validateArrayContents(array, 0);
+  }
+
+  public void testSetJsArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(24);
+    Uint32Array array = TypedArrays.createUint32Array(buf);
+    setFromJsArray(array, 0);
+    validateArrayContents(array, 0);
+
+    buf = TypedArrays.createArrayBuffer(24);
+    array = TypedArrays.createUint32Array(buf);
+    setFromJsArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  /**
+   * Initialize from a JSO rather than a Java array
+   */
+  protected void setFromJsArray(Uint32Array array, int offset) {
+    JsUtils.set(array, getJsoArray(), offset);
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/client/GwtUint8ArrayTest.java b/user/test/com/google/gwt/typedarrays/client/GwtUint8ArrayTest.java
new file mode 100644
index 0000000..0dd6f1f
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/client/GwtUint8ArrayTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JsArrayInteger;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.TypedArrays;
+import com.google.gwt.typedarrays.shared.Uint8Array;
+import com.google.gwt.typedarrays.shared.Uint8ArrayTest;
+
+/**
+ * Test client {@link Uint8Array} implementations.
+ */
+public class GwtUint8ArrayTest extends Uint8ArrayTest {
+
+  private static native JsArrayInteger getJsoArray() /*-{
+    return [ 1, 2, 256, -1 ];
+  }-*/;
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.typedarrays.TypedArraysTest";
+  }
+
+  public void testCreateJsArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    JsArrayInteger src = getJsoArray();
+    Uint8Array array = JsUtils.createUint8Array(src);
+    validateArrayContents(array, 0);
+  }
+
+  public void testSetJsArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(12);
+    Uint8Array array = TypedArrays.createUint8Array(buf);
+    setFromJsArray(array, 0);
+    validateArrayContents(array, 0);
+
+    buf = TypedArrays.createArrayBuffer(12);
+    array = TypedArrays.createUint8Array(buf);
+    setFromJsArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  /**
+   * Initialize from a JSO rather than a Java array
+   */
+  protected void setFromJsArray(Uint8Array array, int offset) {
+    JsUtils.set(array, getJsoArray(), offset);
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/client/GwtUint8ClampedArrayTest.java b/user/test/com/google/gwt/typedarrays/client/GwtUint8ClampedArrayTest.java
new file mode 100644
index 0000000..4c19e3a
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/client/GwtUint8ClampedArrayTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.core.client.JsArrayInteger;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.Uint8ClampedArray;
+import com.google.gwt.typedarrays.shared.Uint8ClampedArrayTest;
+import com.google.gwt.typedarrays.shared.TypedArrays;
+
+/**
+ * Test client {@link Uint8ClampedArray} implementations.
+ */
+public class GwtUint8ClampedArrayTest extends Uint8ClampedArrayTest {
+
+  private static native JsArrayInteger getJsoArray() /*-{
+    return [ 1, 2, 256, -1 ];
+  }-*/;
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.typedarrays.TypedArraysTest";
+  }
+
+  /**
+   * Test creating from a JS array object.
+   */
+  public void testCreateJsArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    JsArrayInteger src = getJsoArray();
+    Uint8ClampedArray array = JsUtils.createUint8ClampedArray(src);
+    validateArrayContents(array, 0);
+  }
+
+  /**
+   * Test setting a native array from a non-native array.
+   */
+  public void testNonNativeSet() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    Uint8ClampedArray dest = TypedArrays.createUint8ClampedArray(6);
+    Uint8ClampedArray src = Uint8ClampedArrayNativeEmul.create(new short[] {
+        1, 2, 256, -1,
+    });
+    dest.set(src, 1);
+    validateArrayContents(dest, 1);
+  }
+
+  /**
+   * Test setting from a JS array object.
+   */
+  public void testSetJsArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(12);
+    Uint8ClampedArray array = TypedArrays.createUint8ClampedArray(buf);
+    setFromJsArray(array, 0);
+    validateArrayContents(array, 0);
+
+    buf = TypedArrays.createArrayBuffer(12);
+    array = TypedArrays.createUint8ClampedArray(buf);
+    setFromJsArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  /**
+   * Initialize from a JSO rather than a Java array
+   */
+  protected void setFromJsArray(Uint8ClampedArray array, int offset) {
+    JsUtils.set(array, getJsoArray(), offset);
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/client/StringArrayBufferTest.java b/user/test/com/google/gwt/typedarrays/client/StringArrayBufferTest.java
new file mode 100644
index 0000000..6bd51fc
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/client/StringArrayBufferTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.client;
+
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.typedarrays.shared.ArrayBuffer;
+import com.google.gwt.typedarrays.shared.TypedArrays;
+import com.google.gwt.typedarrays.shared.Uint8Array;
+
+/**
+ * Test converting to/from a string encoding of an array buffer.
+ */
+public class StringArrayBufferTest extends GWTTestCase {
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.typedarrays.TypedArraysTest";
+  }
+
+  public void testFromString() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    String str = "\u0001\u0000\u0080\u0081";
+    ArrayBuffer buf = JsUtils.arrayBufferFromString(str);
+    Uint8Array view = TypedArrays.createUint8Array(buf);
+    assertEquals(4, buf.byteLength());
+    assertEquals(1, view.get(0));
+    assertEquals(0, view.get(1));
+    assertEquals(128, view.get(2));
+    assertEquals(129, view.get(3));
+  }
+
+  public void testToString() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    Uint8Array view = TypedArrays.createUint8Array(4);
+    view.set(0, 1);
+    view.set(1, 0);
+    view.set(2, 128);
+    view.set(3, 129);
+    String str = JsUtils.stringFromArrayBuffer(view.buffer());
+    assertEquals(4, str.length());
+    assertEquals(1, str.charAt(0));
+    assertEquals(0, str.charAt(1));
+    assertEquals(128, str.charAt(2));
+    assertEquals(129, str.charAt(3));
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/shared/DataViewTest.java b/user/test/com/google/gwt/typedarrays/shared/DataViewTest.java
new file mode 100644
index 0000000..31dd1b7
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/shared/DataViewTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Test {@link DataView} implementations.
+ */
+public class DataViewTest extends GWTTestCase {
+
+  public void testBasic() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    int len = 40;
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(len);
+    assertEquals(len, buf.byteLength());
+    DataView view = TypedArrays.createDataView(buf);
+    assertSame(buf, view.buffer());
+    assertEquals(len, view.byteLength());
+    assertEquals(0, view.byteOffset());
+    
+    // check that it is initialized to zeros
+    for (int i = 0; i < len; ++i) {
+      assertEquals(0, view.getUint8(i));
+    }
+
+    // store some data
+    view.setUint8(0, 0x01);
+    view.setUint8(1, 0x20);
+    view.setUint8(2, 0x04);
+    view.setUint8(3, 0x80);
+
+    // read it out as bytes
+    assertEquals(0x01, view.getUint8(0));
+    assertEquals(0x20, view.getUint8(1));
+    assertEquals(0x04, view.getUint8(2));
+    assertEquals(0x80, view.getUint8(3));
+    assertEquals(0x01, view.getInt8(0));
+    assertEquals(0x20, view.getInt8(1));
+    assertEquals(0x04, view.getInt8(2));
+    assertEquals(-128, view.getInt8(3));
+
+    // read it out as 16-bit values
+    assertEquals(0x0120, view.getUint16(0));
+    assertEquals(0x0480, view.getUint16(2));
+    assertEquals(0x2001, view.getUint16(0, true));
+    assertEquals(0x8004, view.getUint16(2, true));
+    assertEquals(0x0120, view.getInt16(0));
+    assertEquals(0x0480, view.getInt16(2));
+    assertEquals(0x2001, view.getInt16(0, true));
+    assertEquals((short) 0x8004, view.getInt16(2, true));
+
+    // read it out as 32-bit values
+    assertEquals(0x01200480L, view.getUint32(0));
+    assertEquals(0x80042001L, view.getUint32(0, true));
+    assertEquals(0x01200480, view.getInt32(0));
+    assertEquals(0x80042001, view.getInt32(0, true));
+  }
+
+  @Override
+  public String getModuleName() {
+    // returns null for a pure Java test
+    return null;
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/shared/Float32ArrayTest.java b/user/test/com/google/gwt/typedarrays/shared/Float32ArrayTest.java
new file mode 100644
index 0000000..ffe52d4
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/shared/Float32ArrayTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Test {@link Float32Array} implementations.
+ */
+public class Float32ArrayTest extends GWTTestCase {
+  
+  private static final int BYTES_PER_ELEMENT = Float32Array.BYTES_PER_ELEMENT;
+
+  @Override
+  public String getModuleName() {
+    // returns null for a pure Java test
+    return null;
+  }
+
+  public void testBasic() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    int byteLen = 40;
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(byteLen);
+    assertEquals(byteLen, buf.byteLength());
+    DataView view = TypedArrays.createDataView(buf);
+    Float32Array array = TypedArrays.createFloat32Array(buf);
+    assertSame(buf, array.buffer());
+    assertEquals(byteLen, array.byteLength());
+    assertEquals(0, array.byteOffset());
+    int len = byteLen / BYTES_PER_ELEMENT;
+    assertEquals(len, array.length());
+    
+    // check that it is initialized to zeros
+    for (int i = 0; i < len; ++i) {
+      assertEquals(0.0f, array.get(i));
+    }
+
+    // store some data
+    for (int i = 0; i < len; ++i) {
+      array.set(i, 1 << (i + 1));
+    }
+
+    // check the underlying buffer
+    for (int i = 0; i < len; ++i) {
+      assertEquals("Byte " + i + ":0", 0, view.getUint8(i * BYTES_PER_ELEMENT));
+      assertEquals("Byte " + i + ":1", 0, view.getUint8(i * BYTES_PER_ELEMENT + 1));
+      assertEquals("Byte " + i + ":2", (i & 1) != 0 ? 128 : 0,
+          view.getUint8(i * BYTES_PER_ELEMENT + 2));
+      assertEquals("Byte " + i + ":3", 64 + (i / 2), view.getUint8(i * BYTES_PER_ELEMENT + 3));
+    }
+
+    // modify the underlying buffer and read it back
+    view.setFloat32(0, -256, true);
+    view.setInt32(4, 0x0000803F);
+    assertEquals(-256f, array.get(0));
+    assertEquals(1.0f, array.get(1));
+  }
+
+  public void testSetFromJavaArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(24);
+    Float32Array array = TypedArrays.createFloat32Array(buf);
+    setFromJavaArray(array, 0);
+    validateArrayContents(array, 0);
+
+    // On Chrome, there is a bug where the first offset is ignored, so this test will fail if there
+    // isn't a test with offset 0 first.
+    // See http://code.google.com/p/chromium/issues/detail?id=109785
+    buf = TypedArrays.createArrayBuffer(24);
+    array = TypedArrays.createFloat32Array(buf);
+    setFromJavaArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  protected void setFromJavaArray(Float32Array array, int offset) {
+    float[] values = new float[] {
+        1.0f, Float.NEGATIVE_INFINITY, Float.NaN, Float.MAX_VALUE,
+    };
+    array.set(values, offset);
+  }
+
+  protected void validateArrayContents(Float32Array array, int offset) {
+    for (int i = 0; i < offset; ++i) {
+      assertEquals("index " + i, 0.0f, array.get(i));
+    }
+    assertEquals("Index " + offset, 1.0f, array.get(offset++));
+    assertTrue("Index " + offset, Float.isInfinite(array.get(offset)));
+    assertTrue("Index " + offset, array.get(offset++) < 0);
+    assertTrue("Index " + offset, Float.isNaN(array.get(offset++)));
+    assertEquals("Index " + offset, Float.MAX_VALUE, array.get(offset++));
+    for (int i = offset + 4; i < array.length(); ++i) {
+      assertEquals("index " + i, 0, array.get(i));
+    }
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/shared/Float64ArrayTest.java b/user/test/com/google/gwt/typedarrays/shared/Float64ArrayTest.java
new file mode 100644
index 0000000..8b769a9
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/shared/Float64ArrayTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Test {@link Float64Array} implementations.
+ */
+public class Float64ArrayTest extends GWTTestCase {
+  
+  private static final int BYTES_PER_ELEMENT = Float64Array.BYTES_PER_ELEMENT;
+
+  @Override
+  public String getModuleName() {
+    // returns null for a pure Java test
+    return null;
+  }
+
+  public void testBasic() {
+    if (!isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    int byteLen = 40;
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(byteLen);
+    assertEquals(byteLen, buf.byteLength());
+    DataView view = TypedArrays.createDataView(buf);
+    Float64Array array = TypedArrays.createFloat64Array(buf);
+    assertSame(buf, array.buffer());
+    assertEquals(byteLen, array.byteLength());
+    assertEquals(0, array.byteOffset());
+    int len = byteLen / BYTES_PER_ELEMENT;
+    assertEquals(len, array.length());
+    
+    // check that it is initialized to zeros
+    for (int i = 0; i < len; ++i) {
+      assertEquals(0.0, array.get(i));
+    }
+
+    // store some data
+    for (int i = 0; i < len; ++i) {
+      array.set(i, 1 << (i + 1));
+    }
+
+    // check the underlying buffer
+    for (int i = 0; i < len; ++i) {
+      assertEquals("Byte " + i + ":0", 0, view.getUint8(i * BYTES_PER_ELEMENT));
+      assertEquals("Byte " + i + ":1", 0, view.getUint8(i * BYTES_PER_ELEMENT + 1));
+      assertEquals("Byte " + i + ":2", 0, view.getUint8(i * BYTES_PER_ELEMENT + 2));
+      assertEquals("Byte " + i + ":3", 0, view.getUint8(i * BYTES_PER_ELEMENT + 3));
+      assertEquals("Byte " + i + ":4", 0, view.getUint8(i * BYTES_PER_ELEMENT + 4));
+      assertEquals("Byte " + i + ":5", 0, view.getUint8(i * BYTES_PER_ELEMENT + 5));
+      assertEquals("Byte " + i + ":6", (i & 15) << 4,
+          view.getUint8(i * BYTES_PER_ELEMENT + 6));
+      assertEquals("Byte " + i + ":7", 64 + (i >> 4),
+          view.getUint8(i * BYTES_PER_ELEMENT + 7));
+    }
+
+    // modify the underlying buffer and read it back
+    view.setFloat64(0, -256, true);
+    view.setInt32(12, 0x0000F03F);
+    view.setInt32(8, 0);
+    assertEquals(-256.0, array.get(0));
+    assertEquals(1.0, array.get(1));
+  }
+
+  public void testSetFromJavaArray() {
+    if (!isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(48);
+    Float64Array array = TypedArrays.createFloat64Array(buf);
+    setFromJavaArray(array, 0);
+    validateArrayContents(array, 0);
+
+    // On Chrome, there is a bug where the first offset is ignored, so this test will fail if there
+    // isn't a test with offset 0 first.
+    // See http://code.google.com/p/chromium/issues/detail?id=109785
+    buf = TypedArrays.createArrayBuffer(48);
+    array = TypedArrays.createFloat64Array(buf);
+    setFromJavaArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  /**
+   * Not all browsers support Float64Array despite otherwise supporting typed arrays.
+   * 
+   * @return true if the current environment supports Float64Array
+   */
+  protected boolean isSupported() {
+    return TypedArrays.isSupported();
+  }
+
+  protected void setFromJavaArray(Float64Array array, int offset) {
+    double[] values = new double[] {
+        1.0, Double.NEGATIVE_INFINITY, Double.NaN, Double.MAX_VALUE,
+    };
+    array.set(values, offset);
+  }
+
+  protected void validateArrayContents(Float64Array array, int offset) {
+    for (int i = 0; i < offset; ++i) {
+      assertEquals("index " + i, 0.0, array.get(i));
+    }
+    assertEquals("Index " + offset, 1.0, array.get(offset++));
+    assertTrue("Index " + offset, Double.isInfinite(array.get(offset)));
+    assertTrue("Index " + offset, array.get(offset++) < 0);
+    assertTrue("Index " + offset, Double.isNaN(array.get(offset++)));
+    assertEquals("Index " + offset, Double.MAX_VALUE, array.get(offset++));
+    for (int i = offset + 4; i < array.length(); ++i) {
+      assertEquals("index " + i, 0.0, array.get(i));
+    }
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/shared/Int16ArrayTest.java b/user/test/com/google/gwt/typedarrays/shared/Int16ArrayTest.java
new file mode 100644
index 0000000..56fea7e
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/shared/Int16ArrayTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Test {@link Int16Array} implementations.
+ */
+public class Int16ArrayTest extends GWTTestCase {
+  
+  private static final int BYTES_PER_ELEMENT = Int16Array.BYTES_PER_ELEMENT;
+
+  protected void setFromJavaIntArray(Int16Array array, int offset) {
+    int[] values = new int[] {
+        1, 2, 65536, -1,
+    };
+    array.set(values, offset);
+  }
+
+  protected void validateArrayContents(Int16Array array, int offset) {
+    for (int i = 0; i < offset; ++i) {
+      assertEquals("index " + i, 0, array.get(i));
+    }
+    assertEquals("Index " + offset, 1, array.get(offset++));
+    assertEquals("Index " + offset, 2, array.get(offset++));
+    assertEquals("Index " + offset, 0, array.get(offset++));
+    assertEquals("Index " + offset, -1, array.get(offset++));
+    for (int i = offset + 4; i < array.length(); ++i) {
+      assertEquals("index " + i, 0, array.get(i));
+    }
+  }
+
+  public void testBasic() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    int byteLen = 40;
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(byteLen);
+    assertEquals(byteLen, buf.byteLength());
+    DataView view = TypedArrays.createDataView(buf);
+    Int16Array array = TypedArrays.createInt16Array(buf);
+    assertSame(buf, array.buffer());
+    assertEquals(byteLen, array.byteLength());
+    assertEquals(0, array.byteOffset());
+    int len = byteLen / BYTES_PER_ELEMENT;
+    assertEquals(len, array.length());
+    
+    // check that it is initialized to zeros
+    for (int i = 0; i < len; ++i) {
+      assertEquals(0, array.get(i));
+    }
+
+    // store some data
+    for (int i = 0; i < len; ++i) {
+      array.set(i, 0x200 + i);
+    }
+
+    // check the underlying buffer
+    for (int i = 0; i < len; ++i) {
+      assertEquals(i, view.getUint8(i * BYTES_PER_ELEMENT));
+      assertEquals(2, view.getUint8(i * BYTES_PER_ELEMENT + 1));
+    }
+
+    // modify the underlying buffer and read it back
+    view.setInt16(0, -256, true);
+    view.setInt16(2, 128);
+    assertEquals(-256, array.get(0));
+    assertEquals(-32768, array.get(1));
+  }
+
+  public void testSetFromJavaArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(12);
+    Int16Array array = TypedArrays.createInt16Array(buf);
+    setFromJavaIntArray(array, 0);
+    validateArrayContents(array, 0);
+
+    // On Chrome, there is a bug where the first offset is ignored, so this test will fail if there
+    // isn't a test with offset 0 first.
+    // See http://code.google.com/p/chromium/issues/detail?id=109785
+    buf = TypedArrays.createArrayBuffer(12);
+    array = TypedArrays.createInt16Array(buf);
+    setFromJavaIntArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  @Override
+  public String getModuleName() {
+    // returns null for a pure Java test
+    return null;
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/shared/Int32ArrayTest.java b/user/test/com/google/gwt/typedarrays/shared/Int32ArrayTest.java
new file mode 100644
index 0000000..ee55500
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/shared/Int32ArrayTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Test {@link Int32Array} implementations.
+ */
+public class Int32ArrayTest extends GWTTestCase {
+  
+  private static final int BYTES_PER_ELEMENT = Int32Array.BYTES_PER_ELEMENT;
+
+  protected void setFromJavaIntArray(Int32Array array, int offset) {
+    int[] values = new int[] {
+        1, 2, 65536, -1,
+    };
+    array.set(values, offset);
+  }
+
+  protected void validateArrayContents(Int32Array array, int offset) {
+    for (int i = 0; i < offset; ++i) {
+      assertEquals("index " + i, 0, array.get(i));
+    }
+    assertEquals("Index " + offset, 1, array.get(offset++));
+    assertEquals("Index " + offset, 2, array.get(offset++));
+    assertEquals("Index " + offset, 65536, array.get(offset++));
+    assertEquals("Index " + offset, -1, array.get(offset++));
+    for (int i = offset + 4; i < array.length(); ++i) {
+      assertEquals("index " + i, 0, array.get(i));
+    }
+  }
+
+  public void testBasic() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    int byteLen = 40;
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(byteLen);
+    assertEquals(byteLen, buf.byteLength());
+    DataView view = TypedArrays.createDataView(buf);
+    Int32Array array = TypedArrays.createInt32Array(buf);
+    assertSame(buf, array.buffer());
+    assertEquals(byteLen, array.byteLength());
+    assertEquals(0, array.byteOffset());
+    int len = byteLen / BYTES_PER_ELEMENT;
+    assertEquals(len, array.length());
+    
+    // check that it is initialized to zeros
+    for (int i = 0; i < len; ++i) {
+      assertEquals(0, array.get(i));
+    }
+
+    // store some data
+    for (int i = 0; i < len; ++i) {
+      array.set(i, 0x04030200 + i);
+    }
+
+    // check the underlying buffer
+    for (int i = 0; i < len; ++i) {
+      assertEquals(i, view.getUint8(i * BYTES_PER_ELEMENT));
+      assertEquals(2, view.getUint8(i * BYTES_PER_ELEMENT + 1));
+      assertEquals(3, view.getUint8(i * BYTES_PER_ELEMENT + 2));
+      assertEquals(4, view.getUint8(i * BYTES_PER_ELEMENT + 3));
+    }
+
+    // modify the underlying buffer and read it back
+    view.setInt32(0, -256, true);
+    view.setInt32(4, 128);
+    assertEquals(-256, array.get(0));
+    assertEquals(-2147483648, array.get(1));
+  }
+
+  public void testSetFromJavaArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(24);
+    Int32Array array = TypedArrays.createInt32Array(buf);
+    setFromJavaIntArray(array, 0);
+    validateArrayContents(array, 0);
+
+    // On Chrome, there is a bug where the first offset is ignored, so this test will fail if there
+    // isn't a test with offset 0 first.
+    // See http://code.google.com/p/chromium/issues/detail?id=109785
+    buf = TypedArrays.createArrayBuffer(24);
+    array = TypedArrays.createInt32Array(buf);
+    setFromJavaIntArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  @Override
+  public String getModuleName() {
+    // returns null for a pure Java test
+    return null;
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/shared/Int8ArrayTest.java b/user/test/com/google/gwt/typedarrays/shared/Int8ArrayTest.java
new file mode 100644
index 0000000..1388255
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/shared/Int8ArrayTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Test {@link Int8Array} implementations.
+ */
+public class Int8ArrayTest extends GWTTestCase {
+  
+  private static final int BYTES_PER_ELEMENT = Int8Array.BYTES_PER_ELEMENT;
+
+  protected void setFromJavaIntArray(Int8Array array, int offset) {
+    int[] values = new int[] {
+        1, 2, 256, -1,
+    };
+    array.set(values, offset);
+  }
+
+  protected void validateArrayContents(Int8Array array, int offset) {
+    for (int i = 0; i < offset; ++i) {
+      assertEquals("index " + i, 0, array.get(i));
+    }
+    assertEquals("Index " + offset, 1, array.get(offset++));
+    assertEquals("Index " + offset, 2, array.get(offset++));
+    assertEquals("Index " + offset, 0, array.get(offset++));
+    assertEquals("Index " + offset, -1, array.get(offset++));
+    for (int i = offset + 4; i < array.length(); ++i) {
+      assertEquals("index " + i, 0, array.get(i));
+    }
+  }
+
+  public void testBasic() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    int byteLen = 40;
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(byteLen);
+    assertEquals(byteLen, buf.byteLength());
+    DataView view = TypedArrays.createDataView(buf);
+    Int8Array array = TypedArrays.createInt8Array(buf);
+    assertSame(buf, array.buffer());
+    assertEquals(byteLen, array.byteLength());
+    assertEquals(0, array.byteOffset());
+    int len = byteLen / BYTES_PER_ELEMENT;
+    assertEquals(len, array.length());
+    
+    // check that it is initialized to zeros
+    for (int i = 0; i < len; ++i) {
+      assertEquals(0, array.get(i));
+    }
+
+    // store some data
+    for (int i = 0; i < len; ++i) {
+      array.set(i, 0x20 + i);
+    }
+
+    // check the underlying buffer
+    for (int i = 0; i < len; ++i) {
+      assertEquals(0x20 + i, view.getUint8(i));
+    }
+
+    // modify the underlying buffer and read it back
+    view.setInt8(0, -256);
+    view.setInt8(1, -128);
+    assertEquals(0, array.get(0));
+    assertEquals(-128, array.get(1));
+  }
+
+  public void testSetFromJavaArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(6);
+    Int8Array array = TypedArrays.createInt8Array(buf);
+    setFromJavaIntArray(array, 0);
+    validateArrayContents(array, 0);
+
+    // On Chrome, there is a bug where the first offset is ignored, so this test will fail if there
+    // isn't a test with offset 0 first.
+    // See http://code.google.com/p/chromium/issues/detail?id=109785
+    buf = TypedArrays.createArrayBuffer(6);
+    array = TypedArrays.createInt8Array(buf);
+    setFromJavaIntArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  @Override
+  public String getModuleName() {
+    // returns null for a pure Java test
+    return null;
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/shared/Uint16ArrayTest.java b/user/test/com/google/gwt/typedarrays/shared/Uint16ArrayTest.java
new file mode 100644
index 0000000..eb71bcf
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/shared/Uint16ArrayTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Test {@link Uint16Array} implementations.
+ */
+public class Uint16ArrayTest extends GWTTestCase {
+  
+  private static final int BYTES_PER_ELEMENT = Uint16Array.BYTES_PER_ELEMENT;
+
+  protected void setFromJavaIntArray(Uint16Array array, int offset) {
+    int[] values = new int[] {
+        1, 2, 65536, -1,
+    };
+    array.set(values, offset);
+  }
+
+  protected void validateArrayContents(Uint16Array array, int offset) {
+    for (int i = 0; i < offset; ++i) {
+      assertEquals("index " + i, 0, array.get(i));
+    }
+    assertEquals("Index " + offset, 1, array.get(offset++));
+    assertEquals("Index " + offset, 2, array.get(offset++));
+    assertEquals("Index " + offset, 0, array.get(offset++));
+    assertEquals("Index " + offset, 65535, array.get(offset++));
+    for (int i = offset + 4; i < array.length(); ++i) {
+      assertEquals("index " + i, 0, array.get(i));
+    }
+  }
+
+  public void testBasic() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    int byteLen = 40;
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(byteLen);
+    assertEquals(byteLen, buf.byteLength());
+    DataView view = TypedArrays.createDataView(buf);
+    Int16Array array = TypedArrays.createInt16Array(buf);
+    assertSame(buf, array.buffer());
+    assertEquals(byteLen, array.byteLength());
+    assertEquals(0, array.byteOffset());
+    int len = byteLen / BYTES_PER_ELEMENT;
+    assertEquals(len, array.length());
+    
+    // check that it is initialized to zeros
+    for (int i = 0; i < len; ++i) {
+      assertEquals(0, array.get(i));
+    }
+
+    // store some data
+    for (int i = 0; i < len; ++i) {
+      array.set(i, 0x200 + i);
+    }
+
+    // check the underlying buffer
+    for (int i = 0; i < len; ++i) {
+      assertEquals(i, view.getUint8(i * BYTES_PER_ELEMENT));
+      assertEquals(2, view.getUint8(i * BYTES_PER_ELEMENT + 1));
+    }
+
+    // modify the underlying buffer and read it back
+    view.setInt16(0, -256, true);
+    view.setInt16(2, 128);
+    assertEquals(-256, array.get(0));
+    assertEquals(-32768, array.get(1));
+  }
+
+  public void testSetFromJavaArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(12);
+    Uint16Array array = TypedArrays.createUint16Array(buf);
+    setFromJavaIntArray(array, 0);
+    validateArrayContents(array, 0);
+
+    // On Chrome, there is a bug where the first offset is ignored, so this test will fail if there
+    // isn't a test with offset 0 first.
+    // See http://code.google.com/p/chromium/issues/detail?id=109785
+    buf = TypedArrays.createArrayBuffer(12);
+    array = TypedArrays.createUint16Array(buf);
+    setFromJavaIntArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  @Override
+  public String getModuleName() {
+    // returns null for a pure Java test
+    return null;
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/shared/Uint32ArrayTest.java b/user/test/com/google/gwt/typedarrays/shared/Uint32ArrayTest.java
new file mode 100644
index 0000000..545c205
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/shared/Uint32ArrayTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Test {@link Uint32Array} implementations.
+ */
+public class Uint32ArrayTest extends GWTTestCase {
+  
+  private static final int BYTES_PER_ELEMENT = Uint32Array.BYTES_PER_ELEMENT;
+
+  protected void setFromJavaLongArray(Uint32Array array, int offset) {
+    long[] values = new long[] {
+        1, 2, 65536, -1,
+    };
+    array.set(values, offset);
+  }
+
+  protected void setFromJavaDoubleArray(Uint32Array array, int offset) {
+    double[] values = new double[] {
+        1, 2, 65536, -1,
+    };
+    array.set(values, offset);
+  }
+
+  protected void validateArrayContents(Uint32Array array, int offset) {
+    for (int i = 0; i < offset; ++i) {
+      assertEquals("index " + i, 0, array.get(i));
+    }
+    assertEquals("Index " + offset, 1, array.get(offset++));
+    assertEquals("Index " + offset, 2, array.get(offset++));
+    assertEquals("Index " + offset, 65536, array.get(offset++));
+    assertEquals("Index " + offset, 0xFFFFFFFFL, array.get(offset++));
+    for (int i = offset + 4; i < array.length(); ++i) {
+      assertEquals("index " + i, 0, array.get(i));
+    }
+  }
+
+  public void testBasic() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    int byteLen = 40;
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(byteLen);
+    assertEquals(byteLen, buf.byteLength());
+    DataView view = TypedArrays.createDataView(buf);
+    Uint32Array array = TypedArrays.createUint32Array(buf);
+    assertSame(buf, array.buffer());
+    assertEquals(byteLen, array.byteLength());
+    assertEquals(0, array.byteOffset());
+    int len = byteLen / BYTES_PER_ELEMENT;
+    assertEquals(len, array.length());
+    
+    // check that it is initialized to zeros
+    for (int i = 0; i < len; ++i) {
+      assertEquals(0, array.get(i));
+    }
+
+    // store some data
+    for (int i = 0; i < len; ++i) {
+      array.set(i, 0x04030200 + i);
+    }
+
+    // check the underlying buffer
+    for (int i = 0; i < len; ++i) {
+      assertEquals(i, view.getUint8(i * BYTES_PER_ELEMENT));
+      assertEquals(2, view.getUint8(i * BYTES_PER_ELEMENT + 1));
+      assertEquals(3, view.getUint8(i * BYTES_PER_ELEMENT + 2));
+      assertEquals(4, view.getUint8(i * BYTES_PER_ELEMENT + 3));
+    }
+
+    // modify the underlying buffer and read it back
+    view.setInt32(0, -256, true);
+    view.setInt32(4, 128);
+    assertEquals(0xFFFFFF00L, array.get(0));
+    assertEquals(0x80000000L, array.get(1));
+  }
+
+  public void testSetFromJavaLongArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(24);
+    Uint32Array array = TypedArrays.createUint32Array(buf);
+    setFromJavaLongArray(array, 0);
+    validateArrayContents(array, 0);
+
+    // On Chrome, there is a bug where the first offset is ignored, so this test will fail if there
+    // isn't a test with offset 0 first.
+    // See http://code.google.com/p/chromium/issues/detail?id=109785
+    buf = TypedArrays.createArrayBuffer(24);
+    array = TypedArrays.createUint32Array(buf);
+    setFromJavaLongArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  public void testSetFromJavaDoubleArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(24);
+    Uint32Array array = TypedArrays.createUint32Array(buf);
+    setFromJavaDoubleArray(array, 0);
+    validateArrayContents(array, 0);
+
+    // On Chrome, there is a bug where the first offset is ignored, so this test will fail if there
+    // isn't a test with offset 0 first.
+    // See http://code.google.com/p/chromium/issues/detail?id=109785
+    buf = TypedArrays.createArrayBuffer(24);
+    array = TypedArrays.createUint32Array(buf);
+    setFromJavaDoubleArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  @Override
+  public String getModuleName() {
+    // returns null for a pure Java test
+    return null;
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/shared/Uint8ArrayTest.java b/user/test/com/google/gwt/typedarrays/shared/Uint8ArrayTest.java
new file mode 100644
index 0000000..f9eb190
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/shared/Uint8ArrayTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Test {@link Uint8Array} implementations.
+ */
+public class Uint8ArrayTest extends GWTTestCase {
+  
+  private static final int BYTES_PER_ELEMENT = Uint8Array.BYTES_PER_ELEMENT;
+
+  protected void setFromJavaIntArray(Uint8Array array, int offset) {
+    int[] values = new int[] {
+        1, 2, 256, -1,
+    };
+    array.set(values, offset);
+  }
+
+  protected void validateArrayContents(Uint8Array array, int offset) {
+    for (int i = 0; i < offset; ++i) {
+      assertEquals("index " + i, 0, array.get(i));
+    }
+    assertEquals("Index " + offset, 1, array.get(offset++));
+    assertEquals("Index " + offset, 2, array.get(offset++));
+    assertEquals("Index " + offset, 0, array.get(offset++));
+    assertEquals("Index " + offset, 255, array.get(offset++));
+    for (int i = offset + 4; i < array.length(); ++i) {
+      assertEquals("index " + i, 0, array.get(i));
+    }
+  }
+
+  public void testBasic() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    int byteLen = 40;
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(byteLen);
+    assertEquals(byteLen, buf.byteLength());
+    DataView view = TypedArrays.createDataView(buf);
+    Uint8Array array = TypedArrays.createUint8Array(buf);
+    assertSame(buf, array.buffer());
+    assertEquals(byteLen, array.byteLength());
+    assertEquals(0, array.byteOffset());
+    int len = byteLen / BYTES_PER_ELEMENT;
+    assertEquals(len, array.length());
+    
+    // check that it is initialized to zeros
+    for (int i = 0; i < len; ++i) {
+      assertEquals(0, array.get(i));
+    }
+
+    // store some data
+    for (int i = 0; i < len; ++i) {
+      array.set(i, 0x20 + i);
+    }
+
+    // check the underlying buffer
+    for (int i = 0; i < len; ++i) {
+      assertEquals(0x20 + i, view.getUint8(i));
+    }
+
+    // modify the underlying buffer and read it back
+    view.setInt8(0, -256);
+    view.setInt8(1, -128);
+    assertEquals(0, array.get(0));
+    assertEquals(128, array.get(1));
+  }
+
+  public void testSetFromJavaArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(6);
+    Uint8Array array = TypedArrays.createUint8Array(buf);
+    setFromJavaIntArray(array, 0);
+    validateArrayContents(array, 0);
+
+    // On Chrome, there is a bug where the first offset is ignored, so this test will fail if there
+    // isn't a test with offset 0 first.
+    // See http://code.google.com/p/chromium/issues/detail?id=109785
+    buf = TypedArrays.createArrayBuffer(6);
+    array = TypedArrays.createUint8Array(buf);
+    setFromJavaIntArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  @Override
+  public String getModuleName() {
+    // returns null for a pure Java test
+    return null;
+  }
+}
diff --git a/user/test/com/google/gwt/typedarrays/shared/Uint8ClampedArrayTest.java b/user/test/com/google/gwt/typedarrays/shared/Uint8ClampedArrayTest.java
new file mode 100644
index 0000000..1e54569
--- /dev/null
+++ b/user/test/com/google/gwt/typedarrays/shared/Uint8ClampedArrayTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.typedarrays.shared;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Test {@link Uint8ClampedArray} implementations.
+ */
+public class Uint8ClampedArrayTest extends GWTTestCase {
+  
+  private static final int BYTES_PER_ELEMENT = Uint8ClampedArray.BYTES_PER_ELEMENT;
+
+  protected void setFromJavaIntArray(Uint8ClampedArray array, int offset) {
+    int[] values = new int[] {
+        1, 2, 256, -1,
+    };
+    array.set(values, offset);
+  }
+
+  protected void validateArrayContents(Uint8ClampedArray array, int offset) {
+    for (int i = 0; i < offset; ++i) {
+      assertEquals("index " + i, 0, array.get(i));
+    }
+    assertEquals("Index " + offset, 1, array.get(offset++));
+    assertEquals("Index " + offset, 2, array.get(offset++));
+    assertEquals("Index " + offset, 255, array.get(offset++));
+    assertEquals("Index " + offset, 0, array.get(offset++));
+    for (int i = offset + 4; i < array.length(); ++i) {
+      assertEquals("index " + i, 0, array.get(i));
+    }
+  }
+
+  public void testBasic() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    int byteLen = 40;
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(byteLen);
+    assertEquals(byteLen, buf.byteLength());
+    DataView view = TypedArrays.createDataView(buf);
+    Uint8ClampedArray array = TypedArrays.createUint8ClampedArray(buf);
+    assertSame(buf, array.buffer());
+    assertEquals(byteLen, array.byteLength());
+    assertEquals(0, array.byteOffset());
+    int len = byteLen / BYTES_PER_ELEMENT;
+    assertEquals(len, array.length());
+    
+    // check that it is initialized to zeros
+    for (int i = 0; i < len; ++i) {
+      assertEquals(0, array.get(i));
+    }
+
+    // store some data
+    for (int i = 0; i < len; ++i) {
+      array.set(i, 0x20 + i);
+    }
+
+    // check the underlying buffer
+    for (int i = 0; i < len; ++i) {
+      assertEquals(0x20 + i, view.getUint8(i));
+    }
+
+    // check the underlying buffer after modifying
+    array.set(0, -1);
+    array.set(1, 256);
+    assertEquals(0, view.getInt8(0));
+    assertEquals(-1, view.getInt8(1)); // 0xFF == -1 as a byte
+  }
+
+  public void testSetFromJavaArray() {
+    if (!TypedArrays.isSupported()) {
+      // TODO: some way of showing test as skipped in this case?
+      return;
+    }
+    ArrayBuffer buf = TypedArrays.createArrayBuffer(6);
+    Uint8ClampedArray array = TypedArrays.createUint8ClampedArray(buf);
+    setFromJavaIntArray(array, 0);
+    validateArrayContents(array, 0);
+
+    // On Chrome, there is a bug where the first offset is ignored, so this test will fail if there
+    // isn't a test with offset 0 first.
+    // See http://code.google.com/p/chromium/issues/detail?id=109785
+    buf = TypedArrays.createArrayBuffer(6);
+    array = TypedArrays.createUint8ClampedArray(buf);
+    setFromJavaIntArray(array, 1);
+    validateArrayContents(array, 1);
+  }
+
+  @Override
+  public String getModuleName() {
+    // returns null for a pure Java test
+    return null;
+  }
+}