diff --git a/core/modules/image/js/plugins/drupalimagestyle/plugin.js b/core/modules/image/js/plugins/drupalimagestyle/plugin.js
new file mode 100755
index 0000000..ed0730f
--- /dev/null
+++ b/core/modules/image/js/plugins/drupalimagestyle/plugin.js
@@ -0,0 +1,111 @@
+/**
+ * @file
+ * Drupal Image Style plugin.
+ *
+ * This alters the existing CKEditor image2 widget plugin, which is already
+ * altered by the Drupal Image plugin, to allow for the data-image-style
+ * attribute to be set.
+ *
+ * @ignore
+ */
+
+(function (CKEDITOR) {
+
+  "use strict";
+
+  CKEDITOR.plugins.add('drupalimagestyle', {
+    requires: 'drupalimage',
+
+    beforeInit: function (editor) {
+      // Override the image2 widget definition to handle the additional
+      // data-image-style attributes.
+      editor.on('widgetDefinition', function (event) {
+        var widgetDefinition = event.data;
+        if (widgetDefinition.name !== 'image') {
+          return;
+        }
+        // Override default features definitions for drupalimagestyle.
+        CKEDITOR.tools.extend(widgetDefinition.features, {
+          responsiveimage: {
+            requiredContent: 'img[data-image-style]'
+          }
+        }, true);
+
+        // Override requiredContent & allowedContent.
+        var requiredContent = widgetDefinition.requiredContent.getDefinition();
+        requiredContent.attributes['data-image-style'] = '';
+        widgetDefinition.requiredContent = new CKEDITOR.style(requiredContent);
+        widgetDefinition.allowedContent.img.attributes += ',!data-image-style';
+
+        // Override downcast().
+        var originalDowncast = widgetDefinition.downcast;
+        
+        widgetDefinition.downcast = function (element) {
+          var img = originalDowncast.call(this, element);
+          if (!img) {
+            img = findElementByName(element, 'img');
+          }          
+          img.attributes['data-image-style'] = this.data['data-image-style'];
+          return img;
+        };
+
+        // Override upcast().
+        var originalUpcast = widgetDefinition.upcast;
+        widgetDefinition.upcast = function (element, data) {
+          if (element.name !== 'img' || !element.attributes['data-entity-type'] || !element.attributes['data-entity-uuid']) {
+            return;
+          }
+          // Don't initialize on pasted fake objects.
+          else if (element.attributes['data-cke-realelement']) {
+            return;
+          }
+          element = originalUpcast.call(this, element, data);
+
+          // Parse the data-image-style attribute.
+          data['data-image-style'] = element.attributes['data-image-style'];
+
+          return element;
+        };
+
+        // Protected; keys of the widget data to be sent to the Drupal dialog.
+        // Append to the values defined by the drupalimage plugin.
+        // @see core/modules/ckeditor/js/plugins/drupalimage/plugin.js
+        CKEDITOR.tools.extend(widgetDefinition._mapDataToDialog, {
+          'data-image-style': 'data-image-style'
+        });
+      // Low priority to ensure drupalimage's event handler runs first.
+      }, null, null, 20);
+    }
+  });
+  
+  /**
+   * Finds an element by its name.
+   *
+   * Function will check first the passed element itself and then all its
+   * children in DFS order.
+   *
+   * @param {CKEDITOR.htmlParser.element} element
+   *   The element to search.
+   * @param {string} name
+   *   The element name to search for.
+   *
+   * @return {?CKEDITOR.htmlParser.element}
+   *   The found element, or null.
+   */
+  function findElementByName(element, name) {
+    if (element.name === name) {
+      return element;
+    }
+
+    var found = null;
+    element.forEach(function (el) {
+      if (el.name === name) {
+        found = el;
+        // Stop here.
+        return false;
+      }
+    }, CKEDITOR.NODE_ELEMENT);
+    return found;
+  }
+  
+})(CKEDITOR);
\ No newline at end of file
diff --git a/core/modules/image/src/Plugin/CKEditorPlugin/DrupalImageStyle.php b/core/modules/image/src/Plugin/CKEditorPlugin/DrupalImageStyle.php
new file mode 100755
index 0000000..5919119
--- /dev/null
+++ b/core/modules/image/src/Plugin/CKEditorPlugin/DrupalImageStyle.php
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\image\Plugin\CKEditorPlugin\DrupalImageStyle.
+ */
+
+namespace Drupal\image\Plugin\CKEditorPlugin;
+
+use Drupal\Component\Plugin\PluginBase;
+use Drupal\editor\Entity\Editor;
+use Drupal\ckeditor\CKEditorPluginInterface;
+use Drupal\ckeditor\CKEditorPluginContextualInterface;
+
+/**
+ * Defines the "drupalimagestyle" plugin.
+ *
+ * @CKEditorPlugin(
+ *   id = "drupalimagestyle",
+ *   label = @Translation("Drupal image style"),
+ *   module = "ckeditor"
+ * )
+ */
+class DrupalImageStyle extends PluginBase implements CKEditorPluginInterface, CKEditorPluginContextualInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isInternal() {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDependencies(Editor $editor) {
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLibraries(Editor $editor) {
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFile() {
+    return drupal_get_path('module', 'image') . '/js/plugins/drupalimagestyle/plugin.js';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfig(Editor $editor) {
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isEnabled(Editor $editor) {
+    if (!$editor->hasAssociatedFilterFormat()) {
+      return FALSE;
+    }
+
+    // Automatically enable this plugin if the text format associated with this
+    // text editor uses the filter_imagestyle filter and the DrupalImage button
+    // is enabled.
+    $format = $editor->getFilterFormat();
+    if ($format->filters('filter_imagestyle')->status) {
+      $enabled = FALSE;
+      $settings = $editor->getSettings();
+      foreach ($settings['toolbar']['rows'] as $row) {
+        foreach ($row as $group) {
+          foreach ($group['items'] as $button) {
+            if ($button === 'DrupalImage') {
+              $enabled = TRUE;
+            }
+          }
+        }
+      }
+      return $enabled;
+    }
+
+    return FALSE;
+  }
+
+}
\ No newline at end of file
diff --git a/core/modules/image/src/Plugin/Filter/FilterImageStyle.php b/core/modules/image/src/Plugin/Filter/FilterImageStyle.php
new file mode 100755
index 0000000..f93cf91
--- /dev/null
+++ b/core/modules/image/src/Plugin/Filter/FilterImageStyle.php
@@ -0,0 +1,119 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\image\Plugin\Filter\FilterImageStyle.
+ */
+
+namespace Drupal\image\Plugin\Filter;
+
+use Drupal\Component\Utility\Html;
+use Drupal\Component\Utility\String;
+use Drupal\Component\Utility\Unicode;
+use Drupal\Component\Utility\Xss;
+use Drupal\Core\Annotation\Translation;
+use Drupal\filter\Annotation\Filter;
+use Drupal\filter\FilterProcessResult;
+use Drupal\filter\Plugin\FilterBase;
+
+/**
+ * Provides a filter to render inline images as image styles.
+ *
+ * @Filter(
+ *   id = "filter_imagestyle",
+ *   module = "image",
+ *   title = @Translation("Display image styles"),
+ *   description = @Translation("Uses the data-image-style attribute on &lt;img&gt; tags to display image styles."),
+ *   type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_REVERSIBLE
+ * )
+ */
+class FilterImageStyle extends FilterBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function process($text, $langcode) {
+    $search = array();
+    $replace = array();
+
+    if (stristr($text, 'data-image-style') !== FALSE) {
+      $image_styles = entity_load_multiple('image_style');
+
+      $dom = HTML::load($text);
+      $xpath = new \DOMXPath($dom);
+      foreach ($xpath->query('//*[@data-entity-type="file" and @data-entity-uuid and @data-image-style]') as $node) {
+        $file_uuid = $node->getAttribute('data-entity-uuid');
+        $node->removeAttribute('data-entity-uuid');
+        $image_style_id = $node->getAttribute('data-image-style');
+        $node->removeAttribute('data-image-style');
+
+        // If the image style is not a valid one, then don't transform the HTML.
+        if (empty($file_uuid) || !in_array($image_style_id, array_keys($image_styles))) {
+          continue;
+        }
+
+        $file = \Drupal::entityManager()->loadEntityByUuid('file', $file_uuid);
+
+        // Determine width/height of the source image.
+        $width = $height = NULL;
+        $image = \Drupal::service('image.factory')->get($file->getFileUri());
+        if ($image->isValid()) {
+          $width = $image->getWidth();
+          $height = $image->getHeight();
+        }
+
+        // Make sure all non-regenerated attributes are retained.
+        $node->removeAttribute('width');
+        $node->removeAttribute('height');
+        $node->removeAttribute('src');
+        $attributes = array();
+        for ($i = 0; $i < $node->attributes->length; $i++) {
+          $attr = $node->attributes->item($i);
+          $attributes[$attr->name] = $attr->value;
+        }
+
+        // Re-render as an image style.
+        $image = array(
+          '#theme' => 'image_style',
+          '#style_name' => $image_style_id,
+          '#uri' => $file->getFileUri(),
+          '#width' => $width,
+          '#height' => $height,
+          '#attributes' => $attributes,
+        );
+        $altered_html = drupal_render($image);
+
+        // Load the altered HTML into a new DOMDocument and retrieve the element.
+        $updated_node = HTML::load($altered_html)->getElementsByTagName('body')
+          ->item(0)
+          ->childNodes
+          ->item(0);
+
+        // Import the updated node from the new DOMDocument into the original
+        // one, importing also the child nodes of the updated node.
+        $updated_node = $dom->importNode($updated_node, TRUE);
+        // Finally, replace the original image node with the new image node!
+        $node->parentNode->replaceChild($updated_node, $node);
+      }
+
+      return new FilterProcessResult(HTML::serialize($dom));
+    }
+
+    return new FilterProcessResult($text);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function tips($long = FALSE) {
+    if ($long) {
+      $image_styles = entity_load_multiple('image_style');
+      $list = '<code>' . implode('</code>, <code>', array_keys($image_styles)) . '</code>';
+      return t('
+        <p>You can display images using site-wide styles by adding a <code>data-image-style</code> attribute, whose values is one of the image style machine names: !image-style-machine-name-list.</p>', array('!image-style-machine-name-list' => $list));
+    }
+    else {
+      return t('You can display images using site-wide styles by adding a data-image-style attribute.');
+    }
+  }
+}
\ No newline at end of file
diff --git a/core/modules/responsive_image/js/plugins/drupalresponsiveimagestyle/plugin.js b/core/modules/responsive_image/js/plugins/drupalresponsiveimagestyle/plugin.js
new file mode 100755
index 0000000..161edfe
--- /dev/null
+++ b/core/modules/responsive_image/js/plugins/drupalresponsiveimagestyle/plugin.js
@@ -0,0 +1,111 @@
+/**
+ * @file
+ * Drupal Responsive Image Style plugin.
+ *
+ * This alters the existing CKEditor image2 widget plugin, which is already
+ * altered by the Drupal Image plugin, to data-responsive-image-style attribute
+ * to be set.
+ *
+ * @ignore
+ */
+
+(function (CKEDITOR) {
+
+  "use strict";
+
+  CKEDITOR.plugins.add('drupalresponsiveimagestyle', {
+    requires: 'drupalimage',
+
+    beforeInit: function (editor) {
+      // Override the image2 widget definition to handle the additional
+      // data-responsive-image-style attributes.
+      editor.on('widgetDefinition', function (event) {
+        var widgetDefinition = event.data;
+        if (widgetDefinition.name !== 'image') {
+          return;
+        }
+        // Override default features definitions for drupalresponsiveimagestyle.
+        CKEDITOR.tools.extend(widgetDefinition.features, {
+          responsiveimage: {
+            requiredContent: 'img[data-responsive-image-style]'
+          }
+        }, true);
+
+        // Override requiredContent & allowedContent.
+        var requiredContent = widgetDefinition.requiredContent.getDefinition();
+        requiredContent.attributes['data-responsive-image-style'] = '';
+        widgetDefinition.requiredContent = new CKEDITOR.style(requiredContent);
+        widgetDefinition.allowedContent.img.attributes += ',!data-responsive-image-style';
+
+        // Override downcast().
+        var originalDowncast = widgetDefinition.downcast;
+        widgetDefinition.downcast = function (element) {
+          var img = originalDowncast.call(this, element);
+          if (!img) {
+            img = findElementByName(element, 'img');
+          }
+          img.attributes['data-responsive-image-style'] = this.data['data-responsive-image-style'];
+
+          return img;
+        };
+
+        // Override upcast().
+        var originalUpcast = widgetDefinition.upcast;
+        widgetDefinition.upcast = function (element, data) {
+          if (element.name !== 'img' || !element.attributes['data-entity-type'] || !element.attributes['data-entity-uuid']) {
+            return;
+          }
+          // Don't initialize on pasted fake objects.
+          else if (element.attributes['data-cke-realelement']) {
+            return;
+          }
+          element = originalUpcast.call(this, element, data);
+
+          // Parse the data-responsive-image-style attribute.
+          data['data-responsive-image-style'] = element.attributes['data-responsive-image-style'];
+          
+          return element;
+        };
+
+        // Protected; keys of the widget data to be sent to the Drupal dialog.
+        // Append to the values defined by the drupalimage plugin.
+        // @see core/modules/ckeditor/js/plugins/drupalimage/plugin.js
+        CKEDITOR.tools.extend(widgetDefinition._mapDataToDialog, {
+          'data-responsive-image-style': 'data-responsive-image-style',
+        });
+      // Low priority to ensure drupalimage's event handler runs first.
+      }, null, null, 20);
+    }
+  });
+  
+  /**
+   * Finds an element by its name.
+   *
+   * Function will check first the passed element itself and then all its
+   * children in DFS order.
+   *
+   * @param {CKEDITOR.htmlParser.element} element
+   *   The element to search.
+   * @param {string} name
+   *   The element name to search for.
+   *
+   * @return {?CKEDITOR.htmlParser.element}
+   *   The found element, or null.
+   */
+  function findElementByName(element, name) {
+    if (element.name === name) {
+      return element;
+    }
+
+    var found = null;
+    element.forEach(function (el) {
+      if (el.name === name) {
+        found = el;
+        // Stop here.
+        return false;
+      }
+    }, CKEDITOR.NODE_ELEMENT);
+    return found;
+  }
+  
+})(CKEDITOR);
\ No newline at end of file
diff --git a/core/modules/responsive_image/responsive_image.install b/core/modules/responsive_image/responsive_image.install
new file mode 100755
index 0000000..532a580
--- /dev/null
+++ b/core/modules/responsive_image/responsive_image.install
@@ -0,0 +1,27 @@
+<?php
+/**
+ * @file
+ * Install, update and uninstall functions for the responsive image module.
+ */
+
+/**
+ * Add allowed attributes to existing html filters.
+ */
+function responsive_image_update_8001() {
+  $config_factory = \Drupal::configFactory();
+  foreach ($config_factory->listAll('filter.format') as $name) {
+    $config = $config_factory->getEditable($name);
+    if (!$config->get('filters.filter_responsive_image_style.status')) {
+      continue;
+    }
+    $allowed_html = $config->get('filters.filter_html.settings.allowed_html');
+    $matches = [];
+    if (!empty($allowed_html) && preg_match('/<img([^>]*)>/', $allowed_html, $matches)) {
+      $new_attributes = array_filter(explode(' ', $matches[1]));
+      $new_attributes[] = 'data-responsive-image-style';
+      $allowed_html = preg_replace('/<img([^>]*)>/', '<img ' . implode(' ', array_unique($new_attributes)) . '>', $allowed_html);
+      $config->set('filters.filter_html.settings.allowed_html', $allowed_html);
+      $config->save();
+    }
+  }
+}
\ No newline at end of file
diff --git a/core/modules/responsive_image/src/Plugin/CKEditorPlugin/DrupalResponsiveImageStyle.php b/core/modules/responsive_image/src/Plugin/CKEditorPlugin/DrupalResponsiveImageStyle.php
new file mode 100755
index 0000000..df159b2
--- /dev/null
+++ b/core/modules/responsive_image/src/Plugin/CKEditorPlugin/DrupalResponsiveImageStyle.php
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\responsive_image\Plugin\CKEditorPlugin\DrupalResponsiveImageStyle.
+ */
+
+namespace Drupal\responsive_image\Plugin\CKEditorPlugin;
+
+use Drupal\Component\Plugin\PluginBase;
+use Drupal\editor\Entity\Editor;
+use Drupal\ckeditor\CKEditorPluginInterface;
+use Drupal\ckeditor\CKEditorPluginContextualInterface;
+
+/**
+ * Defines the "drupalresponsiveimagestyle" plugin.
+ *
+ * @CKEditorPlugin(
+ *   id = "drupalresponsiveimagestyle",
+ *   label = @Translation("Drupal responsive image style"),
+ *   module = "ckeditor"
+ * )
+ */
+class DrupalResponsiveImageStyle extends PluginBase implements CKEditorPluginInterface, CKEditorPluginContextualInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isInternal() {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDependencies(Editor $editor) {
+    return array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLibraries(Editor $editor) {
+    return array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFile() {
+    return drupal_get_path('module', 'responsive_image') . '/js/plugins/drupalresponsiveimagestyle/plugin.js';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfig(Editor $editor) {
+    return array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isEnabled(Editor $editor) {
+    if (!$editor->hasAssociatedFilterFormat()) {
+      return FALSE;
+    }
+
+    // Automatically enable this plugin if the text format associated with this
+    // text editor uses the filter_responsive_image_style filter and the
+    // DrupalImage button is enabled.
+    $format = $editor->getFilterFormat();
+    if ($format->filters('filter_responsive_image_style')->status) {
+      $enabled = FALSE;
+      $settings = $editor->getSettings();
+      foreach ($settings['toolbar']['rows'] as $row) {
+        foreach ($row as $group) {
+          foreach ($group['items'] as $button) {
+            if ($button === 'DrupalImage') {
+              $enabled = TRUE;
+            }
+          }
+        }
+      }
+      return $enabled;
+    }
+
+    return FALSE;
+  }
+
+}
\ No newline at end of file
diff --git a/core/modules/responsive_image/src/Plugin/Filter/FilterResponsiveImageStyle.php b/core/modules/responsive_image/src/Plugin/Filter/FilterResponsiveImageStyle.php
new file mode 100755
index 0000000..b8c6eda
--- /dev/null
+++ b/core/modules/responsive_image/src/Plugin/Filter/FilterResponsiveImageStyle.php
@@ -0,0 +1,123 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\responsive_image\Plugin\Filter\FilterResponsiveImageStyle.
+ */
+
+namespace Drupal\responsive_image\Plugin\Filter;
+
+use Drupal\Component\Utility\Html;
+use Drupal\filter\Annotation\Filter;
+use Drupal\filter\FilterProcessResult;
+use Drupal\filter\Plugin\FilterBase;
+
+/**
+ * Provides a filter to render inline images as responsive images.
+ *
+ * @Filter(
+ *   id = "filter_responsive_image_style",
+ *   module = "responsive_image",
+ *   title = @Translation("Display responsive images"),
+ *   description = @Translation("Uses the data-responsive-image-style attribute on &lt;img&gt; tags to display responsive images."),
+ *   type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_REVERSIBLE
+ * )
+ */
+class FilterResponsiveImageStyle extends FilterBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function process($text, $langcode) {
+    $search = array();
+    $replace = array();
+
+    if (stristr($text, 'data-responsive-image-style') !== FALSE) {
+      $responsive_image_styes = entity_load_multiple('responsive_image_style');
+
+      $dom = Html::load($text);
+      $xpath = new \DOMXPath($dom);
+      foreach ($xpath->query('//*[@data-entity-uuid and @data-responsive-image-style]') as $node) {
+        $file_uuid = $node->getAttribute('data-entity-uuid');
+        $node->removeAttribute('data-entity-uuid');
+        $responsive_image_style_id = $node->getAttribute('data-responsive-image-style');
+        $node->removeAttribute('data-responsive-image-style');
+
+        // If the responsive image style is not a valid one, then don't
+        // transform the HTML.
+        if (empty($file_uuid) || !in_array($responsive_image_style_id, array_keys($responsive_image_styes))) {
+          continue;
+        }
+
+        $file = \Drupal::entityManager()->loadEntityByUuid('file', $file_uuid);
+
+        // Determine width/height of images that don't have such attributes set.
+        $width = $node->getAttribute('width');
+        $height = $node->getAttribute('height');
+        if (empty($width) || empty($height)) {
+          $image = \Drupal::service('image.factory')->get($file->getFileUri());
+          if ($image->isValid()) {
+            if (empty($width)) {
+              $width = $image->getWidth();
+            }
+            if (empty($height)) {
+              $height = $image->getHeight();
+            }
+          }
+        }
+
+        // Make sure all non-regenerated attributes are retained.
+        $node->removeAttribute('width');
+        $node->removeAttribute('height');
+        $node->removeAttribute('src');
+        $attributes = array();
+        for ($i = 0; $i < $node->attributes->length; $i++) {
+          $attr = $node->attributes->item($i);
+          $attributes[$attr->name] = $attr->value;
+        }
+
+        // Re-render as a responsive image.
+        $responsive_image = array(
+          '#theme' => 'responsive_image',
+          '#uri' => $file->getFileUri(),
+          '#width' => $width,
+          '#height' => $height,
+          '#attributes' => $attributes,
+          '#responsive_image_style_id' => $responsive_image_style_id,
+        );
+        $altered_html = drupal_render($responsive_image);
+
+        // Load the altered HTML into a new DOMDocument and retrieve the element.
+        $updated_node = Html::load(trim($altered_html))->getElementsByTagName('body')
+          ->item(0)
+          ->childNodes
+          ->item(0);
+
+        // Import the updated node from the new DOMDocument into the original
+        // one, importing also the child nodes of the updated node.
+        $updated_node = $dom->importNode($updated_node, TRUE);
+        // Finally, replace the original image node with the new image node!
+        $node->parentNode->replaceChild($updated_node, $node);
+      }
+
+      return new FilterProcessResult(Html::serialize($dom));
+    }
+
+    return new FilterProcessResult($text);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function tips($long = FALSE) {
+    if ($long) {
+      $responsive_image_styles = entity_load_multiple('responsive_image_style');
+      $list = '<code>' . implode('</code>, <code>', array_keys($responsive_image_styles)) . '</code>';
+      return t('
+        <p>You can make images responsive by adding a <code>data-responsive-image-style</code> attribute, whose values is one of the responsive image style machine names: !responsive-image-style-machine-name-list.</p>', array('!responsive-image-style-machine-name-list' => $list));
+    }
+    else {
+      return t('You can make images responsive by adding a data-responsive-image-style attribute.');
+    }
+  }
+}
\ No newline at end of file
