Fixed DOMRectList not having a prototype field.

TBR=vsm@google.com

Change-Id: I6cbc38bbb2123b914d5b5511774425c403e614ed
Reviewed-on: https://dart-review.googlesource.com/47183
Reviewed-by: Terry Lucas <terry@google.com>
Commit-Queue: Terry Lucas <terry@google.com>
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 5955357..f76fa2e 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -15884,6 +15884,24 @@
   @deprecated
   void enteredView() {}
 
+  @DomName('Element.getClientRects')
+  @DocsEditable()
+  @Returns('DomRectList|Null')
+  @Creates('DomRectList')
+  List<Rectangle> getClientRects() {
+    var value = _getClientRects();
+
+    // If no prototype we need one for the world to hookup to the proper Dart class.
+    var jsProto = JS('', '#.prototype', value);
+    if (jsProto == null) {
+      JS('', '#.prototype = Object.create(null)', value);
+    }
+
+    applyExtension('DOMRectList', value);
+
+    return value;
+  }
+
   /** *Deprecated*: override [detached] instead. */
   @Experimental()
   @deprecated
@@ -17634,6 +17652,7 @@
   @Returns('_DomRect|Null')
   Rectangle getBoundingClientRect() native;
 
+  @JSName('getClientRects')
   /**
    * Returns a list of bounding rectangles for each box associated with this
    * element.
@@ -17650,7 +17669,7 @@
   @DocsEditable()
   @Returns('DomRectList|Null')
   @Creates('DomRectList')
-  List<Rectangle> getClientRects() native;
+  List<Rectangle> _getClientRects() native;
 
   /**
    * Returns a list of shadow DOM insertion points to which this element is
@@ -33600,11 +33619,12 @@
   @DocsEditable()
   Rectangle getBoundingClientRect() native;
 
+  @JSName('getClientRects')
   @DomName('Range.getClientRects')
   @DocsEditable()
   @Returns('DomRectList|Null')
   @Creates('DomRectList')
-  List<Rectangle> getClientRects() native;
+  List<Rectangle> _getClientRects() native;
 
   @DomName('Range.insertNode')
   @DocsEditable()
@@ -33650,6 +33670,24 @@
   @DocsEditable()
   void surroundContents(Node newParent) native;
 
+  @DomName('Range.getClientRects')
+  @DocsEditable()
+  @Returns('DomRectList|Null')
+  @Creates('DomRectList')
+  List<Rectangle> getClientRects() {
+    var value = _getClientRects();
+
+    // If no prototype we need one for the world to hookup to the proper Dart class.
+    var jsProto = JS('', '#.prototype', value);
+    if (jsProto == null) {
+      JS('', '#.prototype = Object.create(null)', value);
+    }
+
+    applyExtension('DOMRectList', value);
+
+    return value;
+  }
+
   /**
    * Checks if createContextualFragment is supported.
    *
diff --git a/tests/lib_2/html/client_rect_test.dart b/tests/lib_2/html/client_rect_test.dart
index 19b8569..10d84b2 100644
--- a/tests/lib_2/html/client_rect_test.dart
+++ b/tests/lib_2/html/client_rect_test.dart
@@ -3,7 +3,14 @@
 import 'package:expect/minitest.dart';
 
 main() {
-  var isRectList = predicate((x) => x is DomRectList, 'is a DomRectList');
+  var isRectList =
+      predicate((x) => x is DomRectList, 'should be a DomRectList');
+  var isListOfRectangle =
+      predicate((x) => x is List<Rectangle>, 'should be a List<Rectangle>');
+
+  var isRectangle = predicate((x) => x is Rectangle, 'should be a Rectangle');
+  var isDomRectReadOnly =
+      predicate((x) => x is DomRectReadOnly, 'should be a DomRectReadOnly');
 
   insertTestDiv() {
     var element = new Element.tag('div');
@@ -16,16 +23,19 @@
     return element;
   }
 
-  test("ClientRectList test", () {
+  test("DomRectList test", () {
     insertTestDiv();
     var range = new Range();
     var rects = range.getClientRects();
+    expect(rects, isListOfRectangle);
     expect(rects, isRectList);
   });
 
   test("ClientRect ==", () {
     var rect1 = document.body.getBoundingClientRect();
     var rect2 = document.body.getBoundingClientRect();
+    expect(rect1, isRectangle);
+    expect(rect1, isDomRectReadOnly);
     expect(rect1, equals(rect2));
   });
 }
diff --git a/tests/lib_2/lib_2_dartdevc.status b/tests/lib_2/lib_2_dartdevc.status
index 202fa54..d3e9fe3 100644
--- a/tests/lib_2/lib_2_dartdevc.status
+++ b/tests/lib_2/lib_2_dartdevc.status
@@ -61,7 +61,6 @@
 convert/utf85_test: Slow, Pass
 html/async_spawnuri_test: RuntimeError # Issue 29922
 html/async_test: RuntimeError # Issue 29922
-html/client_rect_test: RuntimeError # Issue 29922, seems to be a reified type problem with DOMClientRect
 html/custom/attribute_changed_callback_test: Skip # Issue 31577
 html/custom/constructor_calls_created_synchronously_test: Skip # Issue 31577
 html/custom/created_callback_test: RuntimeError
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index f29b360..9033552 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -339,6 +339,7 @@
   'Element.children',
   'Element.childElementCount',
   'Element.firstElementChild',
+  'Element.getClientRects',
   'Element.getElementsByTagName',
   'Element.insertAdjacentHTML',
   'Element.scrollIntoView',
@@ -420,6 +421,7 @@
   'ParentNode.firstElementChild',
   'ParentNode.lastElementChild',
   'ParentNode.querySelectorAll',
+  'Range.getClientRects',
   'RTCPeerConnection.createAnswer',
   'RTCPeerConnection.createOffer',
   'RTCPeerConnection.getStats',
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index 4ec5836..47d2ce3 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -782,6 +782,24 @@
   @deprecated
   void enteredView() {}
 
+  @DomName('Element.getClientRects')
+  @DocsEditable()
+  @Returns('DomRectList|Null')
+  @Creates('DomRectList')
+  List<Rectangle> getClientRects() {
+    var value = _getClientRects();
+
+    // If no prototype we need one for the world to hookup to the proper Dart class.
+    var jsProto = JS('', '#.prototype', value);
+    if (jsProto == null) {
+      JS('', '#.prototype = Object.create(null)', value);
+    }
+
+    applyExtension('DOMRectList', value);
+
+    return value;
+  }
+
   /** *Deprecated*: override [detached] instead. */
   @Experimental()
   @deprecated
diff --git a/tools/dom/templates/html/impl/impl_Range.darttemplate b/tools/dom/templates/html/impl/impl_Range.darttemplate
index 82ddf8b..64d01a1 100644
--- a/tools/dom/templates/html/impl/impl_Range.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Range.darttemplate
@@ -13,6 +13,24 @@
       document._caretRangeFromPoint(point.x, point.y);
 $!MEMBERS
 
+  @DomName('Range.getClientRects')
+  @DocsEditable()
+  @Returns('DomRectList|Null')
+  @Creates('DomRectList')
+  List<Rectangle> getClientRects() {
+    var value = _getClientRects();
+
+    // If no prototype we need one for the world to hookup to the proper Dart class.
+    var jsProto = JS('', '#.prototype', value);
+    if (jsProto == null) {
+      JS('', '#.prototype = Object.create(null)', value);
+    }
+
+    applyExtension('DOMRectList', value);
+
+    return value;
+  }
+
   /**
    * Checks if createContextualFragment is supported.
    *