| Index: sdk/lib/html/dartium/html_dartium.dart
 | 
| diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
 | 
| index 6d84226de82586655c9f7a3df4df51566f9711e0..a4d3eb755b61d0b3ac9a44b42ab3225d92542bc8 100644
 | 
| --- a/sdk/lib/html/dartium/html_dartium.dart
 | 
| +++ b/sdk/lib/html/dartium/html_dartium.dart
 | 
| @@ -1116,7 +1116,7 @@ void _addCustomElementType(String tagName, Type dartClass, [String extendTag]) {
 | 
|  }
 | 
|  
 | 
|  Type _getCustomElementType(object) {
 | 
| -  var entry = _knownCustomElements[_getCustomElementName(object)];
 | 
| +  var entry = _getCustomElementEntry(object);
 | 
|    if (entry != null) {
 | 
|      return entry['type'];
 | 
|    }
 | 
| @@ -1124,14 +1124,53 @@ Type _getCustomElementType(object) {
 | 
|  }
 | 
|  
 | 
|  String _getCustomElementExtends(object) {
 | 
| -  var entry = _knownCustomElements[_getCustomElementName(object)];
 | 
| +  var entry = _getCustomElementEntry(object);
 | 
|    if (entry != null) {
 | 
|      return entry['extends'];
 | 
|    }
 | 
|    return null;
 | 
|  }
 | 
|  
 | 
| -_getCustomElement(object) => _knownCustomElements[_getCustomElementName(object)];
 | 
| +_getCustomElementEntry(element) {
 | 
| +  var hasAttribute = false;
 | 
| +
 | 
| +  var jsObject;
 | 
| +  var tag = "";
 | 
| +  var runtimeType = element.runtimeType;
 | 
| +  if (runtimeType == HtmlElement) {
 | 
| +    tag = element.localName;
 | 
| +  } else if (runtimeType == TemplateElement) {
 | 
| +    // Data binding with a Dart class.
 | 
| +    tag = element.attributes['is'];
 | 
| +  } else if (runtimeType == js.JsObjectImpl) {
 | 
| +    // It's a Polymer core element (written in JS).
 | 
| +    // Make sure it's an element anything else we can ignore.
 | 
| +    if (element.hasProperty('nodeType') && element['nodeType'] == 1) {
 | 
| +      if (js.JsNative.callMethod(element, 'hasAttribute', ['is'])) {
 | 
| +        hasAttribute = true;
 | 
| +        // It's data binding use the is attribute.
 | 
| +        tag = js.JsNative.callMethod(element, 'getAttribute', ['is']);
 | 
| +      } else {
 | 
| +        // It's a custom element we want the local name.
 | 
| +        tag = element['localName'];
 | 
| +      }
 | 
| +    }
 | 
| +  } else {
 | 
| +    throw new UnsupportedError('Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObjectImpl.');
 | 
| +  }
 | 
| +
 | 
| +  var entry = _knownCustomElements[tag];
 | 
| +  if (entry != null) {
 | 
| +    // If there's an 'is' attribute then check if the extends tag registered
 | 
| +    // matches the tag if so then return the entry that's registered for this
 | 
| +    // extendsTag or if there's no 'is' tag then return the entry found.
 | 
| +    if ((hasAttribute && entry['extends'] == tag) || !hasAttribute) {
 | 
| +      return entry;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  return null;
 | 
| +}
 | 
|  
 | 
|  // Return the tag name or is attribute of the custom element or data binding.
 | 
|  String _getCustomElementName(element) {
 | 
| @@ -1206,18 +1245,19 @@ wrap_jso(jsObject) {
 | 
|      var wrapper = js.getDartHtmlWrapperFor(jsObject);
 | 
|      // if we have a wrapper return the Dart instance.
 | 
|      if (wrapper != null) {
 | 
| -      if (wrapper.runtimeType == HtmlElement && !wrapper._isBadUpgrade) {
 | 
| -        // We're a Dart instance but we need to upgrade.
 | 
| -        var customElementClass = _getCustomElementType(wrapper);
 | 
| -        if (customElementClass != null) {
 | 
| -          var dartClass_instance;
 | 
| -          try {
 | 
| -            dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
 | 
| -          } finally {
 | 
| -            dartClass_instance.blink_jsObject = jsObject;
 | 
| -            jsObject['dart_class'] = dartClass_instance;
 | 
| -            js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
 | 
| -            return dartClass_instance;
 | 
| +      var customElementClass = _getCustomElementType(wrapper.blink_jsObject);
 | 
| +      if (wrapper.runtimeType != customElementClass && customElementClass != null) {
 | 
| +        if (wrapper.runtimeType == HtmlElement && !wrapper._isBadUpgrade) {
 | 
| +          // We're a Dart instance if it's HtmlElement and we have a customElement
 | 
| +          // class then we need to upgrade.
 | 
| +          if (customElementClass != null) {
 | 
| +            var dartClass_instance;
 | 
| +            try {
 | 
| +              dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
 | 
| +            } finally {
 | 
| +              dartClass_instance.blink_jsObject = jsObject;
 | 
| +              return dartClass_instance;
 | 
| +            }
 | 
|            }
 | 
|          }
 | 
|        }
 | 
| @@ -1255,49 +1295,39 @@ wrap_jso(jsObject) {
 | 
|      }
 | 
|  
 | 
|      var dartClass_instance;
 | 
| -    if (jsObject.hasProperty('dart_class')) {
 | 
| -      // Got a dart_class (it's a custom element) use it it's already set up
 | 
| -      // make sure it's upgraded.
 | 
| -      dartClass_instance = _upgradeHtmlElement(jsObject['dart_class']);
 | 
| +    var customElementClass = null;
 | 
| +    var extendsTag = "";
 | 
| +    var custom = _getCustomElementEntry(jsObject);
 | 
| +    if (custom != null) {
 | 
| +      customElementClass = custom['type'];
 | 
| +      extendsTag = custom['extends'];
 | 
| +    }
 | 
| +
 | 
| +    // Custom Element to upgrade.
 | 
| +    if (customElementClass != null && extendsTag == "") {
 | 
| +      try {
 | 
| +        dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
 | 
| +      } finally {
 | 
| +        dartClass_instance.blink_jsObject = jsObject;
 | 
| +        js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
 | 
| +     }
 | 
|      } else {
 | 
| -      var customElementClass = null;
 | 
| -      var extendsTag = "";
 | 
| -      var custom = _getCustomElement(jsObject);
 | 
| -      if (custom != null) {
 | 
| -        customElementClass = custom['type'];
 | 
| -        extendsTag = custom['extends'];
 | 
| -      }
 | 
| -      // Custom Element to upgrade.
 | 
| -      if (jsTypeName == 'HTMLElement' && customElementClass != null && extendsTag == "") {
 | 
| -        try {
 | 
| -          dartClass_instance = _blink.Blink_Utils.constructElement(customElementClass, jsObject);
 | 
| -        } finally {
 | 
| -          dartClass_instance.blink_jsObject = jsObject;
 | 
| -          jsObject['dart_class'] = dartClass_instance;
 | 
| -          js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
 | 
| -       }
 | 
| -      } else {
 | 
| -        // TODO(terry): Verify with jakemacd that this is right?
 | 
| -        // If we every get an auto-binding we're matching previous non-JS Interop
 | 
| -        // did to return a TemplateElement.
 | 
| +      var func = getHtmlCreateFunction(jsTypeName);
 | 
| +      if (func == null) {
 | 
|          if (jsTypeName == 'auto-binding') {
 | 
| -          jsTypeName = "HTMLTemplateElement";
 | 
| -        }
 | 
| -
 | 
| -        var func = getHtmlCreateFunction(jsTypeName);
 | 
| -        if (func == null) {
 | 
| +          func = getHtmlCreateFunction("HTMLTemplateElement");
 | 
| +        } else if (jsObject.toString() == "[object HTMLElement]") {
 | 
|            // One last ditch effort could be a JS custom element.
 | 
| -          if (jsObject.toString() == "[object HTMLElement]") {
 | 
| -            func = getHtmlCreateFunction("HTMLElement");
 | 
| -          }
 | 
| -        }
 | 
| -        if (func != null) {
 | 
| -          dartClass_instance = func();
 | 
| -          dartClass_instance.blink_jsObject = jsObject;
 | 
| -          js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
 | 
| +          func = getHtmlCreateFunction("HTMLElement");
 | 
|          }
 | 
|        }
 | 
| +      if (func != null) {
 | 
| +        dartClass_instance = func();
 | 
| +        dartClass_instance.blink_jsObject = jsObject;
 | 
| +        js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
 | 
| +      }
 | 
|      }
 | 
| +
 | 
|      // TODO(jacobr): cache that this is not a dart:html JS class.
 | 
|      return dartClass_instance;
 | 
|    } catch(e, stacktrace){
 | 
| @@ -1429,7 +1459,6 @@ _upgradeHtmlElement(dartInstance) {
 | 
|          dartInstance._badUpgrade();
 | 
|        } finally {
 | 
|          dartInstance.blink_jsObject = jsObject;
 | 
| -        jsObject['dart_class'] = dartInstance;
 | 
|          js.setDartHtmlWrapperFor(jsObject, dartInstance);
 | 
|       }
 | 
|     }
 | 
| @@ -9327,7 +9356,7 @@ class CustomEvent extends Event {
 | 
|      }
 | 
|  
 | 
|      // Need for identity.
 | 
| -    e.blink_jsObject['dart_class'] = e;
 | 
| +    js.setDartHtmlWrapperFor(e.blink_jsObject, e);
 | 
|  
 | 
|      return e;
 | 
|    }
 | 
| @@ -20322,12 +20351,28 @@ class HtmlDocument extends Document {
 | 
|      return isElement ? jsClassName : null;
 | 
|    }
 | 
|  
 | 
| +  // Get the first class that's a super of a dart.dom library.
 | 
| +  ClassMirror _getDartHtmlClassName(ClassMirror classMirror) {
 | 
| +    while (classMirror.superclass != null) {
 | 
| +      var fullName = classMirror.superclass.qualifiedName;
 | 
| +      var domLibrary = MirrorSystem.getName(fullName).startsWith('dart.dom.');
 | 
| +      if (domLibrary) {
 | 
| +        return classMirror.superclass;
 | 
| +      }
 | 
| +
 | 
| +      classMirror = classMirror.superclass;
 | 
| +    }
 | 
| +
 | 
| +    return null;
 | 
| +  }
 | 
| +
 | 
|    /**
 | 
|     * Get the class that immediately derived from a class in dart:html or
 | 
|     * dart:svg (has an attribute DomName of either HTML* or SVG*).
 | 
|     */
 | 
|    ClassMirror _getDomSuperClass(ClassMirror classMirror) {
 | 
|      var isElement = false;
 | 
| +    var foundSuperElement = null;
 | 
|  
 | 
|      while (classMirror.superclass != null) {
 | 
|        var fullName = classMirror.superclass.qualifiedName;
 | 
| @@ -20335,6 +20380,9 @@ class HtmlDocument extends Document {
 | 
|  
 | 
|        var domLibrary = MirrorSystem.getName(fullName).startsWith('dart.dom.');
 | 
|        if (domLibrary) {
 | 
| +        if (foundSuperElement == null) {
 | 
| +          foundSuperElement = classMirror.superclass;
 | 
| +        }
 | 
|          // Lookup JS class (if not found).
 | 
|          var metadatas = classMirror.metadata;
 | 
|          for (var metadata in metadatas) {
 | 
| @@ -20342,7 +20390,7 @@ class HtmlDocument extends Document {
 | 
|            var metaType = reflectClass(metaDataMirror.runtimeType);
 | 
|            if (MirrorSystem.getName(metaType.simpleName) == 'DomName' &&
 | 
|                (metaDataMirror.name.startsWith('HTML') || metaDataMirror.name.startsWith('SVG'))) {
 | 
| -            if (isElement) return classMirror;
 | 
| +            if (isElement) return foundSuperElement;
 | 
|            }
 | 
|          }
 | 
|        }
 | 
| @@ -20463,6 +20511,25 @@ class HtmlDocument extends Document {
 | 
|        throw new DomException.jsInterop("HierarchyRequestError: Only HTML elements can be customized.");
 | 
|      }
 | 
|  
 | 
| +    var customClassType = _getDartHtmlClassName(classMirror);
 | 
| +
 | 
| +    if (extendsTag != null) {
 | 
| +      var nativeElement = document.createElement(extendsTag);
 | 
| +
 | 
| +      // Trying to extend a native element is it the Dart class consistent with the
 | 
| +      // extendsTag? 
 | 
| +      if (nativeElement.runtimeType != customClassType.reflectedType) {
 | 
| +        var nativeElementClassMirror = reflectClass(nativeElement.runtimeType);
 | 
| +        var customClassNativeElement = MirrorSystem.getName(customClassType.simpleName);
 | 
| +        var extendsNativeElement = MirrorSystem.getName(nativeElementClassMirror.simpleName);
 | 
| +        throw new DomException.jsInterop("HierarchyRequestError: Custom class type ($customClassNativeElement) and extendsTag class ($extendsNativeElement) don't match .");
 | 
| +      }
 | 
| +    } else if (customClassType.reflectedType != HtmlElement && customClassType.reflectedType != svg.SvgElement) {
 | 
| +      var customClassName = MirrorSystem.getName(classMirror.simpleName);
 | 
| +      var customClassElement = MirrorSystem.getName(customClassType.simpleName);
 | 
| +      throw new DomException.jsInterop("HierarchyRequestError: Custom element $customClassName is a native $customClassElement should be derived from HtmlElement or SvgElement.");
 | 
| +    }
 | 
| +
 | 
|      if (_hasCreatedConstructor(classMirror)) {
 | 
|        // Start the hookup the JS way create an <x-foo> element that extends the
 | 
|        // <x-base> custom element. Inherit its prototype and signal what tag is
 | 
| @@ -20499,9 +20566,26 @@ class HtmlDocument extends Document {
 | 
|  
 | 
|            var dartClass;
 | 
|            try {
 | 
| +            if (extendsTag != null) {
 | 
| +              // If we're extending a native element then create that element.
 | 
| +              // Then upgrade that element to the customElementClass through
 | 
| +              // normal flow.
 | 
| +              dartClass = document.createElement(extendsTag);
 | 
| +              js.setDartHtmlWrapperFor($this, dartClass);
 | 
| +              dartClass.blink_jsObject = $this;
 | 
| +            }
 | 
| +
 | 
| +            // Upgrade to the CustomElement Dart class.
 | 
|              dartClass = _blink.Blink_Utils.constructElement(customElementClass, $this);
 | 
|            } catch (e) {
 | 
| +            // Got a problem make it an HtmlElement and rethrow the error.
 | 
|              dartClass = HtmlElement.internalCreateHtmlElement();
 | 
| +            // We need to remember the JS object (because constructElement failed
 | 
| +            // it normally sets up the blink_jsObject.
 | 
| +            dartClass.blink_jsObject = $this;
 | 
| +
 | 
| +            // Mark to only try this once don't try upgrading from HtmlElement
 | 
| +            // to the user's Dart class - we had a problem.
 | 
|              dartClass._badUpgrade();
 | 
|              throw e;
 | 
|            } finally {
 | 
| @@ -47163,9 +47247,11 @@ class _VariableSizeListIterator<T> implements Iterator<T> {
 | 
|  class _VMElementUpgrader implements ElementUpgrader {
 | 
|    final Type _type;
 | 
|    final Type _nativeType;
 | 
| +  final String _extendsTag;
 | 
|  
 | 
|    _VMElementUpgrader(Document document, Type type, String extendsTag) :
 | 
|        _type = type,
 | 
| +      _extendsTag = extendsTag,
 | 
|        _nativeType = _validateCustomType(type).reflectedType {
 | 
|  
 | 
|      if (extendsTag == null) {
 | 
| @@ -47183,20 +47269,39 @@ class _VMElementUpgrader implements ElementUpgrader {
 | 
|  
 | 
|    Element upgrade(element) {
 | 
|      var jsObject;
 | 
| -    var tag = _getCustomElementName(element);
 | 
| +    var tag;
 | 
| +    var isNativeElementExtension = false;
 | 
| +
 | 
| +    try {
 | 
| +      tag = _getCustomElementName(element);
 | 
| +    } catch (e) {
 | 
| +      isNativeElementExtension = element.localName == _extendsTag;
 | 
| +    }
 | 
| +
 | 
|      if (element.runtimeType == HtmlElement || element.runtimeType == TemplateElement) {
 | 
| +      if (tag != _extendsTag) {
 | 
| +        throw new UnsupportedError('$tag is not registered.');
 | 
| +      }
 | 
|        jsObject = unwrap_jso(element);
 | 
|      } else if (element.runtimeType == js.JsObjectImpl) {
 | 
|        // It's a Polymer core element (written in JS).
 | 
|        jsObject = element;
 | 
| -    } else {
 | 
| +    } else if (isNativeElementExtension) {
 | 
| +      // Extending a native element.
 | 
| +      jsObject = element.blink_jsObject;
 | 
| +
 | 
| +      // Element to extend is the real tag.
 | 
| +      tag = element.localName;
 | 
| +    } else if (tag != null && element.localName != tag) { 
 | 
| +      throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected native Html or Svg element to extend.');
 | 
| +    } else if (tag == null) {
 | 
|        throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected HtmlElement/JsObjectImpl.');
 | 
|      }
 | 
|  
 | 
|      // Remember Dart class to tagName for any upgrading done in wrap_jso.
 | 
| -    _addCustomElementType(tag, _type);
 | 
| +    _addCustomElementType(tag, _type, _extendsTag);
 | 
|  
 | 
| -    return createCustomUpgrader(_nativeType, jsObject);
 | 
| +    return createCustomUpgrader(_type, jsObject);
 | 
|    }
 | 
|  }
 | 
|  
 | 
| 
 |