Merge m-c to autoland, a=merge
authorWes Kocher <wkocher@mozilla.com>
Thu, 23 Feb 2017 16:59:01 -0800
changeset 373574 ddc507c5fa844619f0f8cb3aea6a3fe0c7b4d5bc
parent 373573 45eac3e757c79eb1033101aa0b6491d224835b9d (current diff)
parent 373511 7d50c8e3086d4cd1f05895b3dceac091f8825f1a (diff)
child 373575 fae64acfaddc96696388fbbddae07dda56d34035
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone54.0a1
Merge m-c to autoland, a=merge MozReview-Commit-ID: 2xWBiKMAozs
gfx/webrender/src/layer.rs
gfx/webrender/src/scroll_tree.rs
layout/base/PresShell.cpp
layout/painting/nsCSSRendering.cpp
layout/painting/nsDisplayList.cpp
third_party/rust/app_units-0.3.0/.cargo-checksum.json
third_party/rust/app_units-0.3.0/.cargo-ok
third_party/rust/app_units-0.3.0/.gitignore
third_party/rust/app_units-0.3.0/.travis.yml
third_party/rust/app_units-0.3.0/Cargo.toml
third_party/rust/app_units-0.3.0/README.md
third_party/rust/app_units-0.3.0/src/app_unit.rs
third_party/rust/app_units-0.3.0/src/lib.rs
third_party/rust/bincode/src/rustc_serialize/mod.rs
third_party/rust/bincode/src/rustc_serialize/reader.rs
third_party/rust/bincode/src/rustc_serialize/writer.rs
third_party/rust/dwrote/.cargo-checksum.json
third_party/rust/dwrote/.cargo-ok
third_party/rust/dwrote/.gitignore
third_party/rust/dwrote/Cargo.toml
third_party/rust/dwrote/README.md
third_party/rust/dwrote/build.rs
third_party/rust/dwrote/src/bitmap_render_target.rs
third_party/rust/dwrote/src/com_helpers.rs
third_party/rust/dwrote/src/comptr.rs
third_party/rust/dwrote/src/font.rs
third_party/rust/dwrote/src/font_collection.rs
third_party/rust/dwrote/src/font_face.rs
third_party/rust/dwrote/src/font_family.rs
third_party/rust/dwrote/src/font_file.rs
third_party/rust/dwrote/src/font_file_loader_impl.rs
third_party/rust/dwrote/src/gdi_interop.rs
third_party/rust/dwrote/src/glyph_run_analysis.rs
third_party/rust/dwrote/src/helpers.rs
third_party/rust/dwrote/src/lib.rs
third_party/rust/dwrote/src/rendering_params.rs
third_party/rust/dwrote/src/test.rs
third_party/rust/dwrote/src/types.rs
third_party/rust/euclid-0.10.5/.cargo-checksum.json
third_party/rust/euclid-0.10.5/.cargo-ok
third_party/rust/euclid-0.10.5/.gitignore
third_party/rust/euclid-0.10.5/.travis.yml
third_party/rust/euclid-0.10.5/COPYRIGHT
third_party/rust/euclid-0.10.5/Cargo.toml
third_party/rust/euclid-0.10.5/LICENSE-APACHE
third_party/rust/euclid-0.10.5/LICENSE-MIT
third_party/rust/euclid-0.10.5/README.md
third_party/rust/euclid-0.10.5/src/approxeq.rs
third_party/rust/euclid-0.10.5/src/length.rs
third_party/rust/euclid-0.10.5/src/lib.rs
third_party/rust/euclid-0.10.5/src/macros.rs
third_party/rust/euclid-0.10.5/src/matrix2d.rs
third_party/rust/euclid-0.10.5/src/matrix4d.rs
third_party/rust/euclid-0.10.5/src/num.rs
third_party/rust/euclid-0.10.5/src/point.rs
third_party/rust/euclid-0.10.5/src/rect.rs
third_party/rust/euclid-0.10.5/src/scale_factor.rs
third_party/rust/euclid-0.10.5/src/side_offsets.rs
third_party/rust/euclid-0.10.5/src/size.rs
third_party/rust/euclid-0.10.5/src/trig.rs
third_party/rust/serde-0.8.23/.cargo-checksum.json
third_party/rust/serde-0.8.23/.cargo-ok
third_party/rust/serde-0.8.23/Cargo.toml
third_party/rust/serde-0.8.23/src/bytes.rs
third_party/rust/serde-0.8.23/src/de/from_primitive.rs
third_party/rust/serde-0.8.23/src/de/impls.rs
third_party/rust/serde-0.8.23/src/de/mod.rs
third_party/rust/serde-0.8.23/src/de/value.rs
third_party/rust/serde-0.8.23/src/error.rs
third_party/rust/serde-0.8.23/src/iter.rs
third_party/rust/serde-0.8.23/src/lib.rs
third_party/rust/serde-0.8.23/src/macros.rs
third_party/rust/serde-0.8.23/src/ser/impls.rs
third_party/rust/serde-0.8.23/src/ser/mod.rs
third_party/rust/serde-0.8.23/src/utils.rs
toolkit/library/gtest/rust/Cargo.lock
toolkit/library/rust/Cargo.lock
--- a/build/moz.configure/warnings.configure
+++ b/build/moz.configure/warnings.configure
@@ -73,16 +73,19 @@ check_and_add_gcc_warning('-Wimplicit-fa
 # --enable-warnings-as-errors is specified so that no unexpected fatal
 # warnings are produced.
 check_and_add_gcc_warning('-Werror=non-literal-null-conversion',
                           when='--enable-warnings-as-errors')
 
 # catches string literals used in boolean expressions
 check_and_add_gcc_warning('-Wstring-conversion')
 
+# catches inconsistent use of mutexes
+check_and_add_gcc_warning('-Wthread-safety')
+
 # we inline 'new' and 'delete' in mozalloc
 check_and_add_gcc_warning('-Wno-inline-new-delete', cxx_compiler)
 
 # Prevent the following GCC warnings from being treated as errors:
 # too many false positives
 check_and_add_gcc_warning('-Wno-error=maybe-uninitialized')
 
 # we don't want our builds held hostage when a platform-specific API
--- a/gfx/doc/README.webrender
+++ b/gfx/doc/README.webrender
@@ -74,9 +74,9 @@ there is another crate in m-c called moz
 the same folder to store its rust dependencies. If one of the libraries that is
 required by both mozjs_sys and webrender is updated without updating the other
 project's Cargo.lock file, that results in build bustage.
 This means that any time you do this sort of manual update of packages, you need
 to make sure that mozjs_sys also has its Cargo.lock file updated if needed, hence
 the need to run the cargo update command in js/src as well. Hopefully this will
 be resolved soon.
 
-Latest Commit: 938b32ca93bf5e878422ac4bafcdd53f8058f880
+Latest Commit: edc74274d28b1fa1229a1d1ea05027f57172b992
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -917,27 +917,29 @@ struct ParamTraits<mozilla::layers::Text
 {
   typedef mozilla::layers::TextureFactoryIdentifier paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mParentBackend);
     WriteParam(aMsg, aParam.mParentProcessType);
     WriteParam(aMsg, aParam.mMaxTextureSize);
+    WriteParam(aMsg, aParam.mCompositorUseANGLE);
     WriteParam(aMsg, aParam.mSupportsTextureBlitting);
     WriteParam(aMsg, aParam.mSupportsPartialUploads);
     WriteParam(aMsg, aParam.mSupportsComponentAlpha);
     WriteParam(aMsg, aParam.mSyncHandle);
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
   {
     bool result = ReadParam(aMsg, aIter, &aResult->mParentBackend) &&
                   ReadParam(aMsg, aIter, &aResult->mParentProcessType) &&
                   ReadParam(aMsg, aIter, &aResult->mMaxTextureSize) &&
+                  ReadParam(aMsg, aIter, &aResult->mCompositorUseANGLE) &&
                   ReadParam(aMsg, aIter, &aResult->mSupportsTextureBlitting) &&
                   ReadParam(aMsg, aIter, &aResult->mSupportsPartialUploads) &&
                   ReadParam(aMsg, aIter, &aResult->mSupportsComponentAlpha) &&
                   ReadParam(aMsg, aIter, &aResult->mSyncHandle);
     return result;
   }
 };
 
--- a/gfx/layers/CompositorTypes.h
+++ b/gfx/layers/CompositorTypes.h
@@ -163,31 +163,34 @@ typedef uintptr_t SyncHandle;
  * of the compositor and should (in the future) include information about what
  * kinds of buffer and texture clients to create.
  */
 struct TextureFactoryIdentifier
 {
   LayersBackend mParentBackend;
   GeckoProcessType mParentProcessType;
   int32_t mMaxTextureSize;
+  bool mCompositorUseANGLE;
   bool mSupportsTextureBlitting;
   bool mSupportsPartialUploads;
   bool mSupportsComponentAlpha;
   SyncHandle mSyncHandle;
 
   explicit TextureFactoryIdentifier(LayersBackend aLayersBackend = LayersBackend::LAYERS_NONE,
                                     GeckoProcessType aParentProcessType = GeckoProcessType_Default,
                                     int32_t aMaxTextureSize = 4096,
+                                    bool aCompositorUseANGLE = false,
                                     bool aSupportsTextureBlitting = false,
                                     bool aSupportsPartialUploads = false,
                                     bool aSupportsComponentAlpha = true,
                                     SyncHandle aSyncHandle = 0)
     : mParentBackend(aLayersBackend)
     , mParentProcessType(aParentProcessType)
     , mMaxTextureSize(aMaxTextureSize)
+    , mCompositorUseANGLE(aCompositorUseANGLE)
     , mSupportsTextureBlitting(aSupportsTextureBlitting)
     , mSupportsPartialUploads(aSupportsPartialUploads)
     , mSupportsComponentAlpha(aSupportsComponentAlpha)
     , mSyncHandle(aSyncHandle)
   {}
 };
 
 /**
--- a/gfx/layers/ipc/KnowsCompositor.h
+++ b/gfx/layers/ipc/KnowsCompositor.h
@@ -57,16 +57,21 @@ public:
     return mTextureFactoryIdentifier.mSupportsPartialUploads;
   }
 
   bool SupportsComponentAlpha() const
   {
     return mTextureFactoryIdentifier.mSupportsComponentAlpha;
   }
 
+  bool GetCompositorUseANGLE() const
+  {
+    return mTextureFactoryIdentifier.mCompositorUseANGLE;
+  }
+
   const TextureFactoryIdentifier& GetTextureFactoryIdentifier() const
   {
     return mTextureFactoryIdentifier;
   }
 
   bool DeviceCanReset() const {
     return GetCompositorBackendType() != LayersBackend::LAYERS_BASIC;
   }
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -136,16 +136,17 @@ public:
   virtual void Destroy() override;
 
   virtual TextureFactoryIdentifier GetTextureFactoryIdentifier() override
   {
     TextureFactoryIdentifier result =
       TextureFactoryIdentifier(LayersBackend::LAYERS_OPENGL,
                                XRE_GetProcessType(),
                                GetMaxTextureSize(),
+                               false,
                                mFBOTextureTarget == LOCAL_GL_TEXTURE_2D,
                                SupportsPartialTextureUpdate());
     return result;
   }
 
   virtual already_AddRefed<CompositingRenderTarget>
   CreateRenderTarget(const gfx::IntRect &aRect, SurfaceInitMode aInit) override;
 
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -691,13 +691,14 @@ WebRenderBridgeParent::SetWebRenderProfi
 
 TextureFactoryIdentifier
 WebRenderBridgeParent::GetTextureFactoryIdentifier()
 {
   MOZ_ASSERT(mApi);
 
   return TextureFactoryIdentifier(LayersBackend::LAYERS_WR,
                                   XRE_GetProcessType(),
-                                  mApi->GetMaxTextureSize());
+                                  mApi->GetMaxTextureSize(),
+                                  mApi->GetUseANGLE());
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/webrender/Cargo.toml
+++ b/gfx/webrender/Cargo.toml
@@ -1,46 +1,46 @@
 [package]
 name = "webrender"
-version = "0.15.0"
+version = "0.19.0"
 authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
 license = "MPL-2.0"
 repository = "https://github.com/servo/webrender"
 build = "build.rs"
 
 [features]
 default = ["codegen", "freetype-lib"]
 codegen = ["webrender_traits/codegen"]
 freetype-lib = ["freetype/servo-freetype-sys"]
 serde_derive = ["webrender_traits/serde_derive"]
 profiler = ["thread_profiler/thread_profiler"]
 
 [dependencies]
-app_units = "0.3"
-bincode = "0.6"
+app_units = "0.4"
+bincode = "1.0.0-alpha2"
 bit-set = "0.4"
 byteorder = "1.0"
-euclid = "0.10.3"
+euclid = "0.11"
 fnv="1.0"
 gleam = "0.2.30"
 lazy_static = "0.2"
 log = "0.3"
 num-traits = "0.1.32"
-offscreen_gl_context = {version = "0.5", features = ["serde_serialization", "osmesa"]}
+offscreen_gl_context = {version = "0.6", features = ["serde", "osmesa"]}
 time = "0.1"
 threadpool = "1.3.2"
 webrender_traits = {path = "../webrender_traits", default-features = false}
 bitflags = "0.7"
 gamma-lut = "0.1"
 thread_profiler = "0.1.1"
 
 [dev-dependencies]
 angle = {git = "https://github.com/servo/angle", branch = "servo"}
 
 [target.'cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))'.dependencies]
 freetype = { version = "0.2", default-features = false }
 
 [target.'cfg(target_os = "windows")'.dependencies]
-dwrote = "0.1.7"
+servo-dwrote = "0.2"
 
 [target.'cfg(target_os = "macos")'.dependencies]
-core-graphics = "0.6.0"
-core-text = "3.0"
+core-graphics = "0.7.0"
+core-text = "4.0"
--- a/gfx/webrender/res/cs_text_run.vs.glsl
+++ b/gfx/webrender/res/cs_text_run.vs.glsl
@@ -14,17 +14,17 @@ void main(void) {
     Glyph glyph = fetch_glyph(cpi.sub_index);
     PrimitiveGeometry pg = fetch_prim_geometry(cpi.global_prim_index);
     ResourceRect res = fetch_resource_rect(cpi.user_data.x);
 
     // Glyphs size is already in device-pixels.
     // The render task origin is in device-pixels. Offset that by
     // the glyph offset, relative to its primitive bounding rect.
     vec2 size = res.uv_rect.zw - res.uv_rect.xy;
-    vec2 origin = task.data0.xy + uDevicePixelRatio * (glyph.offset.xy - pg.local_rect.xy);
+    vec2 origin = task.data0.xy + uDevicePixelRatio * (glyph.offset.xy - pg.local_rect.p0);
     vec4 local_rect = vec4(origin, size);
 
     vec2 texture_size = vec2(textureSize(sColor0, 0));
     vec2 st0 = res.uv_rect.xy / texture_size;
     vec2 st1 = res.uv_rect.zw / texture_size;
 
     vec2 pos = mix(local_rect.xy,
                    local_rect.xy + local_rect.zw,
--- a/gfx/webrender/res/prim_shared.glsl
+++ b/gfx/webrender/res/prim_shared.glsl
@@ -81,20 +81,63 @@ ivec2 get_fetch_uv_2(int index) {
 ivec2 get_fetch_uv_4(int index) {
     return get_fetch_uv(index, 4);
 }
 
 ivec2 get_fetch_uv_8(int index) {
     return get_fetch_uv(index, 8);
 }
 
+struct RectWithSize {
+    vec2 p0;
+    vec2 size;
+};
+
+struct RectWithEndpoint {
+    vec2 p0;
+    vec2 p1;
+};
+
+RectWithEndpoint to_rect_with_endpoint(RectWithSize rect) {
+    RectWithEndpoint result;
+    result.p0 = rect.p0;
+    result.p1 = rect.p0 + rect.size;
+
+    return result;
+}
+
+RectWithSize to_rect_with_size(RectWithEndpoint rect) {
+    RectWithSize result;
+    result.p0 = rect.p0;
+    result.size = rect.p1 - rect.p0;
+
+    return result;
+}
+
+vec2 clamp_rect(vec2 point, RectWithSize rect) {
+    return clamp(point, rect.p0, rect.p0 + rect.size);
+}
+
+vec2 clamp_rect(vec2 point, RectWithEndpoint rect) {
+    return clamp(point, rect.p0, rect.p1);
+}
+
+// Clamp 2 points at once.
+vec4 clamp_rect(vec4 points, RectWithSize rect) {
+    return clamp(points, rect.p0.xyxy, rect.p0.xyxy + rect.size.xyxy);
+}
+
+vec4 clamp_rect(vec4 points, RectWithEndpoint rect) {
+    return clamp(points, rect.p0.xyxy, rect.p1.xyxy);
+}
+
 struct Layer {
     mat4 transform;
     mat4 inv_transform;
-    vec4 local_clip_rect;
+    RectWithSize local_clip_rect;
     vec4 screen_vertices[4];
 };
 
 Layer fetch_layer(int index) {
     Layer layer;
 
     // Create a UV base coord for each 8 texels.
     // This is required because trying to use an offset
@@ -109,17 +152,18 @@ Layer fetch_layer(int index) {
     layer.transform[2] = texelFetchOffset(sLayers, uv0, 0, ivec2(2, 0));
     layer.transform[3] = texelFetchOffset(sLayers, uv0, 0, ivec2(3, 0));
 
     layer.inv_transform[0] = texelFetchOffset(sLayers, uv0, 0, ivec2(4, 0));
     layer.inv_transform[1] = texelFetchOffset(sLayers, uv0, 0, ivec2(5, 0));
     layer.inv_transform[2] = texelFetchOffset(sLayers, uv0, 0, ivec2(6, 0));
     layer.inv_transform[3] = texelFetchOffset(sLayers, uv0, 0, ivec2(7, 0));
 
-    layer.local_clip_rect = texelFetchOffset(sLayers, uv1, 0, ivec2(0, 0));
+    vec4 clip_rect = texelFetchOffset(sLayers, uv1, 0, ivec2(0, 0));
+    layer.local_clip_rect = RectWithSize(clip_rect.xy, clip_rect.zw);
 
     layer.screen_vertices[0] = texelFetchOffset(sLayers, uv1, 0, ivec2(1, 0));
     layer.screen_vertices[1] = texelFetchOffset(sLayers, uv1, 0, ivec2(2, 0));
     layer.screen_vertices[2] = texelFetchOffset(sLayers, uv1, 0, ivec2(3, 0));
     layer.screen_vertices[3] = texelFetchOffset(sLayers, uv1, 0, ivec2(4, 0));
 
     return layer;
 }
@@ -241,36 +285,38 @@ Glyph fetch_glyph(int index) {
 
     ivec2 uv = get_fetch_uv_1(index);
 
     glyph.offset = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
 
     return glyph;
 }
 
-vec4 fetch_instance_geometry(int index) {
+RectWithSize fetch_instance_geometry(int index) {
     ivec2 uv = get_fetch_uv_1(index);
 
     vec4 rect = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
 
-    return rect;
+    return RectWithSize(rect.xy, rect.zw);
 }
 
 struct PrimitiveGeometry {
-    vec4 local_rect;
-    vec4 local_clip_rect;
+    RectWithSize local_rect;
+    RectWithSize local_clip_rect;
 };
 
 PrimitiveGeometry fetch_prim_geometry(int index) {
     PrimitiveGeometry pg;
 
     ivec2 uv = get_fetch_uv(index, VECS_PER_PRIM_GEOM);
 
-    pg.local_rect = texelFetchOffset(sPrimGeometry, uv, 0, ivec2(0, 0));
-    pg.local_clip_rect = texelFetchOffset(sPrimGeometry, uv, 0, ivec2(1, 0));
+    vec4 local_rect = texelFetchOffset(sPrimGeometry, uv, 0, ivec2(0, 0));
+    pg.local_rect = RectWithSize(local_rect.xy, local_rect.zw);
+    vec4 local_clip_rect = texelFetchOffset(sPrimGeometry, uv, 0, ivec2(1, 0));
+    pg.local_clip_rect = RectWithSize(local_clip_rect.xy, local_clip_rect.zw);
 
     return pg;
 }
 
 struct PrimitiveInstance {
     int global_prim_index;
     int specific_prim_index;
     int render_task_index;
@@ -317,18 +363,18 @@ CachePrimitiveInstance fetch_cache_insta
 
     return cpi;
 }
 
 struct Primitive {
     Layer layer;
     ClipArea clip_area;
     AlphaBatchTask task;
-    vec4 local_rect;
-    vec4 local_clip_rect;
+    RectWithSize local_rect;
+    RectWithSize local_clip_rect;
     int prim_index;
     // when sending multiple primitives of the same type (e.g. border segments)
     // this index allows the vertex shader to recognize the difference
     int sub_index;
     ivec2 user_data;
     float z;
 };
 
@@ -397,57 +443,38 @@ vec4 get_layer_pos(vec2 pos, Layer layer
     vec3 a = layer.screen_vertices[0].xyz / layer.screen_vertices[0].w;
     vec3 b = layer.screen_vertices[3].xyz / layer.screen_vertices[3].w;
     vec3 c = layer.screen_vertices[2].xyz / layer.screen_vertices[2].w;
     // get the normal to the layer plane
     vec3 n = normalize(cross(b-a, c-a));
     return untransform(pos, n, a, layer.inv_transform);
 }
 
-vec2 clamp_rect(vec2 point, vec4 rect) {
-    return clamp(point, rect.xy, rect.xy + rect.zw);
-}
-
-struct Rect {
-    vec2 p0;
-    vec2 p1;
-};
-
 struct VertexInfo {
-    Rect local_rect;
+    RectWithEndpoint local_rect;
     vec2 local_pos;
     vec2 screen_pos;
 };
 
-VertexInfo write_vertex(vec4 instance_rect,
-                        vec4 local_clip_rect,
+VertexInfo write_vertex(RectWithSize instance_rect,
+                        RectWithSize local_clip_rect,
                         float z,
                         Layer layer,
                         AlphaBatchTask task) {
-    // Get the min/max local space coords of the rectangle.
-    vec2 local_p0 = instance_rect.xy;
-    vec2 local_p1 = instance_rect.xy + instance_rect.zw;
-
-    // Get the min/max coords of the local space clip rect.
-    vec2 local_clip_p0 = local_clip_rect.xy;
-    vec2 local_clip_p1 = local_clip_rect.xy + local_clip_rect.zw;
-
-    // Get the min/max coords of the layer clip rect.
-    vec2 layer_clip_p0 = layer.local_clip_rect.xy;
-    vec2 layer_clip_p1 = layer.local_clip_rect.xy + layer.local_clip_rect.zw;
+    RectWithEndpoint local_rect = to_rect_with_endpoint(instance_rect);
 
     // Select the corner of the local rect that we are processing.
-    vec2 local_pos = mix(local_p0, local_p1, aPosition.xy);
+    vec2 local_pos = mix(local_rect.p0, local_rect.p1, aPosition.xy);
 
     // xy = top left corner of the local rect, zw = position of current vertex.
-    vec4 local_p0_pos = vec4(local_p0, local_pos);
+    vec4 local_p0_pos = vec4(local_rect.p0, local_pos);
 
     // Clamp to the two local clip rects.
-    local_p0_pos = clamp(local_p0_pos, local_clip_p0.xyxy, local_clip_p1.xyxy);
-    local_p0_pos = clamp(local_p0_pos, layer_clip_p0.xyxy, layer_clip_p1.xyxy);
+    local_p0_pos = clamp_rect(local_p0_pos, local_clip_rect);
+    local_p0_pos = clamp_rect(local_p0_pos, layer.local_clip_rect);
 
     // Transform the top corner and current vertex to world space.
     vec4 world_p0 = layer.transform * vec4(local_p0_pos.xy, 0.0, 1.0);
     world_p0.xyz /= world_p0.w;
     vec4 world_pos = layer.transform * vec4(local_p0_pos.zw, 0.0, 1.0);
     world_pos.xyz /= world_pos.w;
 
     // Convert the world positions to device pixel space. xy=top left corner. zw=current vertex.
@@ -459,35 +486,35 @@ VertexInfo write_vertex(vec4 instance_re
     // Apply offsets for the render task to get correct screen location.
     vec2 final_pos = device_p0_pos.zw -
                      snap_delta -
                      task.screen_space_origin +
                      task.render_target_origin;
 
     gl_Position = uTransform * vec4(final_pos, z, 1.0);
 
-    VertexInfo vi = VertexInfo(Rect(local_p0, local_p1), local_p0_pos.zw, device_p0_pos.zw);
+    VertexInfo vi = VertexInfo(local_rect, local_p0_pos.zw, device_p0_pos.zw);
     return vi;
 }
 
 #ifdef WR_FEATURE_TRANSFORM
 
 struct TransformVertexInfo {
     vec3 local_pos;
     vec2 screen_pos;
     vec4 clipped_local_rect;
 };
 
-TransformVertexInfo write_transform_vertex(vec4 instance_rect,
-                                           vec4 local_clip_rect,
+TransformVertexInfo write_transform_vertex(RectWithSize instance_rect,
+                                           RectWithSize local_clip_rect,
                                            float z,
                                            Layer layer,
                                            AlphaBatchTask task) {
-    vec2 lp0_base = instance_rect.xy;
-    vec2 lp1_base = instance_rect.xy + instance_rect.zw;
+    vec2 lp0_base = instance_rect.p0;
+    vec2 lp1_base = instance_rect.p0 + instance_rect.size;
 
     vec2 lp0 = clamp_rect(clamp_rect(lp0_base, local_clip_rect),
                           layer.local_clip_rect);
     vec2 lp1 = clamp_rect(clamp_rect(lp1_base, local_clip_rect),
                           layer.local_clip_rect);
 
     vec4 clipped_local_rect = vec4(lp0, lp1 - lp0);
 
--- a/gfx/webrender/res/ps_border.vs.glsl
+++ b/gfx/webrender/res/ps_border.vs.glsl
@@ -27,110 +27,100 @@ Border fetch_border(int index) {
     return border;
 }
 
 void main(void) {
     Primitive prim = load_primitive();
     Border border = fetch_border(prim.prim_index);
     int sub_part = prim.sub_index;
 
-    vec2 tl_outer = prim.local_rect.xy;
+    vec2 tl_outer = prim.local_rect.p0;
     vec2 tl_inner = tl_outer + vec2(max(border.radii[0].x, border.widths.x),
                                     max(border.radii[0].y, border.widths.y));
 
-    vec2 tr_outer = vec2(prim.local_rect.x + prim.local_rect.z,
-                         prim.local_rect.y);
+    vec2 tr_outer = vec2(prim.local_rect.p0.x + prim.local_rect.size.x,
+                         prim.local_rect.p0.y);
     vec2 tr_inner = tr_outer + vec2(-max(border.radii[0].z, border.widths.z),
                                     max(border.radii[0].w, border.widths.y));
 
-    vec2 br_outer = vec2(prim.local_rect.x + prim.local_rect.z,
-                         prim.local_rect.y + prim.local_rect.w);
+    vec2 br_outer = vec2(prim.local_rect.p0.x + prim.local_rect.size.x,
+                         prim.local_rect.p0.y + prim.local_rect.size.y);
     vec2 br_inner = br_outer - vec2(max(border.radii[1].x, border.widths.z),
                                     max(border.radii[1].y, border.widths.w));
 
-    vec2 bl_outer = vec2(prim.local_rect.x,
-                         prim.local_rect.y + prim.local_rect.w);
+    vec2 bl_outer = vec2(prim.local_rect.p0.x,
+                         prim.local_rect.p0.y + prim.local_rect.size.y);
     vec2 bl_inner = bl_outer + vec2(max(border.radii[1].z, border.widths.x),
                                     -max(border.radii[1].w, border.widths.w));
 
-    vec4 segment_rect;
+    RectWithSize segment_rect;
     switch (sub_part) {
         case PST_TOP_LEFT:
-            segment_rect = vec4(tl_outer, tl_inner - tl_outer);
+            segment_rect.p0 = tl_outer;
+            segment_rect.size = tl_inner - tl_outer;
             vBorderStyle = int(border.style.x);
             vHorizontalColor = border.colors[BORDER_LEFT];
             vVerticalColor = border.colors[BORDER_TOP];
             vRadii = vec4(border.radii[0].xy,
                           border.radii[0].xy - border.widths.xy);
             break;
         case PST_TOP_RIGHT:
-            segment_rect = vec4(tr_inner.x,
-                                tr_outer.y,
-                                tr_outer.x - tr_inner.x,
-                                tr_inner.y - tr_outer.y);
+            segment_rect.p0 = vec2(tr_inner.x, tr_outer.y);
+            segment_rect.size = vec2(tr_outer.x - tr_inner.x, tr_inner.y - tr_outer.y);
             vBorderStyle = int(border.style.y);
             vHorizontalColor = border.colors[BORDER_TOP];
             vVerticalColor = border.colors[BORDER_RIGHT];
             vRadii = vec4(border.radii[0].zw,
                           border.radii[0].zw - border.widths.zy);
             break;
         case PST_BOTTOM_RIGHT:
-            segment_rect = vec4(br_inner, br_outer - br_inner);
+            segment_rect.p0 = br_inner;
+            segment_rect.size = br_outer - br_inner;
             vBorderStyle = int(border.style.z);
             vHorizontalColor = border.colors[BORDER_BOTTOM];
             vVerticalColor = border.colors[BORDER_RIGHT];
             vRadii = vec4(border.radii[1].xy,
                           border.radii[1].xy - border.widths.zw);
             break;
         case PST_BOTTOM_LEFT:
-            segment_rect = vec4(bl_outer.x,
-                                bl_inner.y,
-                                bl_inner.x - bl_outer.x,
-                                bl_outer.y - bl_inner.y);
+            segment_rect.p0 = vec2(bl_outer.x, bl_inner.y);
+            segment_rect.size = vec2(bl_inner.x - bl_outer.x, bl_outer.y - bl_inner.y);
             vBorderStyle = int(border.style.w);
             vHorizontalColor = border.colors[BORDER_BOTTOM];
             vVerticalColor = border.colors[BORDER_LEFT];
             vRadii = vec4(border.radii[1].zw,
                           border.radii[1].zw - border.widths.xw);
             break;
         case PST_LEFT:
-            segment_rect = vec4(tl_outer.x,
-                                tl_inner.y,
-                                border.widths.x,
-                                bl_inner.y - tl_inner.y);
+            segment_rect.p0 = vec2(tl_outer.x, tl_inner.y);
+            segment_rect.size = vec2(border.widths.x, bl_inner.y - tl_inner.y);
             vBorderStyle = int(border.style.x);
             vHorizontalColor = border.colors[BORDER_LEFT];
             vVerticalColor = border.colors[BORDER_LEFT];
             vRadii = vec4(0.0);
             break;
         case PST_RIGHT:
-            segment_rect = vec4(tr_outer.x - border.widths.z,
-                                tr_inner.y,
-                                border.widths.z,
-                                br_inner.y - tr_inner.y);
+            segment_rect.p0 = vec2(tr_outer.x - border.widths.z, tr_inner.y);
+            segment_rect.size = vec2(border.widths.z, br_inner.y - tr_inner.y);
             vBorderStyle = int(border.style.z);
             vHorizontalColor = border.colors[BORDER_RIGHT];
             vVerticalColor = border.colors[BORDER_RIGHT];
             vRadii = vec4(0.0);
             break;
         case PST_BOTTOM:
-            segment_rect = vec4(bl_inner.x,
-                                bl_outer.y - border.widths.w,
-                                br_inner.x - bl_inner.x,
-                                border.widths.w);
+            segment_rect.p0 = vec2(bl_inner.x, bl_outer.y - border.widths.w);
+            segment_rect.size = vec2(br_inner.x - bl_inner.x, border.widths.w);
             vBorderStyle = int(border.style.w);
             vHorizontalColor = border.colors[BORDER_BOTTOM];
             vVerticalColor = border.colors[BORDER_BOTTOM];
             vRadii = vec4(0.0);
             break;
         case PST_TOP:
-            segment_rect = vec4(tl_inner.x,
-                                tl_outer.y,
-                                tr_inner.x - tl_inner.x,
-                                border.widths.y);
+            segment_rect.p0 = vec2(tl_inner.x, tl_outer.y);
+            segment_rect.size = vec2(tr_inner.x - tl_inner.x, border.widths.y);
             vBorderStyle = int(border.style.y);
             vHorizontalColor = border.colors[BORDER_TOP];
             vVerticalColor = border.colors[BORDER_TOP];
             vRadii = vec4(0.0);
             break;
     }
 
 #ifdef WR_FEATURE_TRANSFORM
@@ -147,63 +137,63 @@ void main(void) {
     VertexInfo vi = write_vertex(segment_rect,
                                  prim.local_clip_rect,
                                  prim.z,
                                  prim.layer,
                                  prim.task);
     vLocalPos = vi.local_pos.xy;
 
     // Local space
-    vLocalRect = prim.local_rect;
+    vLocalRect = vec4(prim.local_rect.p0, prim.local_rect.size);
 #endif
 
     float x0, y0, x1, y1;
     switch (sub_part) {
         // These are the layer tile part PrimitivePart as uploaded by the tiling.rs
         case PST_TOP_LEFT:
-            x0 = segment_rect.x;
-            y0 = segment_rect.y;
+            x0 = segment_rect.p0.x;
+            y0 = segment_rect.p0.y;
             // These are width / heights
-            x1 = segment_rect.x + segment_rect.z;
-            y1 = segment_rect.y + segment_rect.w;
+            x1 = segment_rect.p0.x + segment_rect.size.x;
+            y1 = segment_rect.p0.y + segment_rect.size.y;
 
             // The radius here is the border-radius. This is 0, so vRefPoint will
             // just be the top left (x,y) corner.
             vRefPoint = vec2(x0, y0) + vRadii.xy;
             break;
         case PST_TOP_RIGHT:
-            x0 = segment_rect.x + segment_rect.z;
-            y0 = segment_rect.y;
-            x1 = segment_rect.x;
-            y1 = segment_rect.y + segment_rect.w;
+            x0 = segment_rect.p0.x + segment_rect.size.x;
+            y0 = segment_rect.p0.y;
+            x1 = segment_rect.p0.x;
+            y1 = segment_rect.p0.y + segment_rect.size.y;
             vRefPoint = vec2(x0, y0) + vec2(-vRadii.x, vRadii.y);
             break;
         case PST_BOTTOM_LEFT:
-            x0 = segment_rect.x;
-            y0 = segment_rect.y + segment_rect.w;
-            x1 = segment_rect.x + segment_rect.z;
-            y1 = segment_rect.y;
+            x0 = segment_rect.p0.x;
+            y0 = segment_rect.p0.y + segment_rect.size.y;
+            x1 = segment_rect.p0.x + segment_rect.size.x;
+            y1 = segment_rect.p0.y;
             vRefPoint = vec2(x0, y0) + vec2(vRadii.x, -vRadii.y);
             break;
         case PST_BOTTOM_RIGHT:
-            x0 = segment_rect.x;
-            y0 = segment_rect.y;
-            x1 = segment_rect.x + segment_rect.z;
-            y1 = segment_rect.y + segment_rect.w;
+            x0 = segment_rect.p0.x;
+            y0 = segment_rect.p0.y;
+            x1 = segment_rect.p0.x + segment_rect.size.x;
+            y1 = segment_rect.p0.y + segment_rect.size.y;
             vRefPoint = vec2(x1, y1) + vec2(-vRadii.x, -vRadii.y);
             break;
         case PST_TOP:
         case PST_LEFT:
         case PST_BOTTOM:
         case PST_RIGHT:
-            vRefPoint = segment_rect.xy;
-            x0 = segment_rect.x;
-            y0 = segment_rect.y;
-            x1 = segment_rect.x + segment_rect.z;
-            y1 = segment_rect.y + segment_rect.w;
+            vRefPoint = segment_rect.p0.xy;
+            x0 = segment_rect.p0.x;
+            y0 = segment_rect.p0.y;
+            x1 = segment_rect.p0.x + segment_rect.size.x;
+            y1 = segment_rect.p0.y + segment_rect.size.y;
             break;
     }
 
     // y1 - y0 is the height of the corner / line
     // x1 - x0 is the width of the corner / line.
     float width = x1 - x0;
     float height = y1 - y0;
 
--- a/gfx/webrender/res/ps_box_shadow.vs.glsl
+++ b/gfx/webrender/res/ps_box_shadow.vs.glsl
@@ -1,32 +1,32 @@
 #line 1
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 void main(void) {
     Primitive prim = load_primitive();
     BoxShadow bs = fetch_boxshadow(prim.prim_index);
-    vec4 segment_rect = fetch_instance_geometry(prim.sub_index);
+    RectWithSize segment_rect = fetch_instance_geometry(prim.sub_index);
 
     VertexInfo vi = write_vertex(segment_rect,
                                  prim.local_clip_rect,
                                  prim.z,
                                  prim.layer,
                                  prim.task);
 
     RenderTaskData child_task = fetch_render_task(prim.user_data.x);
     vUv.z = child_task.data1.x;
 
     // Constant offsets to inset from bilinear filtering border.
     vec2 patch_origin = child_task.data0.xy + vec2(1.0);
     vec2 patch_size_device_pixels = child_task.data0.zw - vec2(2.0);
     vec2 patch_size = patch_size_device_pixels / uDevicePixelRatio;
 
-    vUv.xy = (vi.local_pos - prim.local_rect.xy) / patch_size;
-    vMirrorPoint = 0.5 * prim.local_rect.zw / patch_size;
+    vUv.xy = (vi.local_pos - prim.local_rect.p0) / patch_size;
+    vMirrorPoint = 0.5 * prim.local_rect.size / patch_size;
 
     vec2 texture_size = vec2(textureSize(sCache, 0));
     vCacheUvRectCoords = vec4(patch_origin, patch_origin + patch_size_device_pixels) / texture_size.xyxy;
 
     vColor = bs.color;
 }
--- a/gfx/webrender/res/ps_cache_image.vs.glsl
+++ b/gfx/webrender/res/ps_cache_image.vs.glsl
@@ -17,12 +17,12 @@ void main(void) {
 
     RenderTaskData child_task = fetch_render_task(prim.user_data.x);
     vUv.z = child_task.data1.x;
 
     vec2 texture_size = vec2(textureSize(sCache, 0));
     vec2 uv0 = child_task.data0.xy / texture_size;
     vec2 uv1 = (child_task.data0.xy + child_task.data0.zw) / texture_size;
 
-    vec2 f = (vi.local_pos - prim.local_rect.xy) / prim.local_rect.zw;
+    vec2 f = (vi.local_pos - prim.local_rect.p0) / prim.local_rect.size;
 
     vUv.xy = mix(uv0, uv1, f);
 }
--- a/gfx/webrender/res/ps_gradient.vs.glsl
+++ b/gfx/webrender/res/ps_gradient.vs.glsl
@@ -5,58 +5,56 @@
 
 void main(void) {
     Primitive prim = load_primitive();
     Gradient gradient = fetch_gradient(prim.prim_index);
 
     GradientStop g0 = fetch_gradient_stop(prim.sub_index + 0);
     GradientStop g1 = fetch_gradient_stop(prim.sub_index + 1);
 
-    vec4 segment_rect;
+    RectWithSize segment_rect;
     vec2 axis;
     if (gradient.start_end_point.y == gradient.start_end_point.w) {
         float x0 = mix(gradient.start_end_point.x,
                        gradient.start_end_point.z,
                        g0.offset.x);
         float x1 = mix(gradient.start_end_point.x,
                        gradient.start_end_point.z,
                        g1.offset.x);
-        segment_rect.yw = prim.local_rect.yw;
-        segment_rect.x = x0;
-        segment_rect.z = x1 - x0;
+        segment_rect.p0 = vec2(x0, prim.local_rect.p0.y);
+        segment_rect.size = vec2(x1 - x0, prim.local_rect.size.y);
         axis = vec2(1.0, 0.0);
     } else {
         float y0 = mix(gradient.start_end_point.y,
                        gradient.start_end_point.w,
                        g0.offset.x);
         float y1 = mix(gradient.start_end_point.y,
                        gradient.start_end_point.w,
                        g1.offset.x);
-        segment_rect.xz = prim.local_rect.xz;
-        segment_rect.y = y0;
-        segment_rect.w = y1 - y0;
+        segment_rect.p0 = vec2(prim.local_rect.p0.x, y0);
+        segment_rect.size = vec2(prim.local_rect.size.x, y1 - y0);
         axis = vec2(0.0, 1.0);
     }
 
 #ifdef WR_FEATURE_TRANSFORM
     TransformVertexInfo vi = write_transform_vertex(segment_rect,
                                                     prim.local_clip_rect,
                                                     prim.z,
                                                     prim.layer,
                                                     prim.task);
     vLocalRect = vi.clipped_local_rect;
     vLocalPos = vi.local_pos;
-    vec2 f = (vi.local_pos.xy - prim.local_rect.xy) / prim.local_rect.zw;
+    vec2 f = (vi.local_pos.xy - prim.local_rect.p0) / prim.local_rect.size;
 #else
     VertexInfo vi = write_vertex(segment_rect,
                                  prim.local_clip_rect,
                                  prim.z,
                                  prim.layer,
                                  prim.task);
 
-    vec2 f = (vi.local_pos - segment_rect.xy) / segment_rect.zw;
+    vec2 f = (vi.local_pos - segment_rect.p0) / segment_rect.size;
     vPos = vi.local_pos;
 #endif
 
     write_clip(vi.screen_pos, prim.clip_area);
 
     vColor = mix(g0.color, g1.color, dot(f, axis));
 }
--- a/gfx/webrender/res/ps_text_run.vs.glsl
+++ b/gfx/webrender/res/ps_text_run.vs.glsl
@@ -4,27 +4,28 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 void main(void) {
     Primitive prim = load_primitive();
     TextRun text = fetch_text_run(prim.prim_index);
     Glyph glyph = fetch_glyph(prim.sub_index);
     ResourceRect res = fetch_resource_rect(prim.user_data.x);
 
-    vec4 local_rect = vec4(glyph.offset.xy, (res.uv_rect.zw - res.uv_rect.xy) / uDevicePixelRatio);
+    RectWithSize local_rect = RectWithSize(glyph.offset.xy,
+                                           (res.uv_rect.zw - res.uv_rect.xy) / uDevicePixelRatio);
 
 #ifdef WR_FEATURE_TRANSFORM
     TransformVertexInfo vi = write_transform_vertex(local_rect,
                                                     prim.local_clip_rect,
                                                     prim.z,
                                                     prim.layer,
                                                     prim.task);
     vLocalRect = vi.clipped_local_rect;
     vLocalPos = vi.local_pos;
-    vec2 f = (vi.local_pos.xy / vi.local_pos.z - local_rect.xy) / local_rect.zw;
+    vec2 f = (vi.local_pos.xy / vi.local_pos.z - local_rect.p0) / local_rect.size;
 #else
     VertexInfo vi = write_vertex(local_rect,
                                  prim.local_clip_rect,
                                  prim.z,
                                  prim.layer,
                                  prim.task);
     vec2 f = (vi.local_pos - vi.local_rect.p0) / (vi.local_rect.p1 - vi.local_rect.p0);
 #endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/src/clip_scroll_node.rs
@@ -0,0 +1,288 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use euclid::Point3D;
+use geometry::ray_intersects_rect;
+use spring::{DAMPING, STIFFNESS, Spring};
+use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform};
+use webrender_traits::{LayerToWorldTransform, PipelineId, ScrollEventPhase, ScrollLayerId};
+use webrender_traits::{ScrollLayerRect, ScrollLocation, ScrollToWorldTransform, WorldPoint};
+use webrender_traits::{WorldPoint4D};
+
+#[cfg(target_os = "macos")]
+const CAN_OVERSCROLL: bool = true;
+
+#[cfg(not(target_os = "macos"))]
+const CAN_OVERSCROLL: bool = false;
+
+
+/// Contains scrolling and transform information stacking contexts.
+#[derive(Clone)]
+pub struct ClipScrollNode {
+    /// Manages scrolling offset, overscroll state etc.
+    pub scrolling: ScrollingState,
+
+    /// Size of the content inside the scroll region (in logical pixels)
+    pub content_size: LayerSize,
+
+    /// Viewing rectangle
+    pub local_viewport_rect: LayerRect,
+
+    /// Viewing rectangle clipped against parent layer(s)
+    pub combined_local_viewport_rect: LayerRect,
+
+    /// World transform for the viewport rect itself.
+    pub world_viewport_transform: LayerToWorldTransform,
+
+    /// World transform for content within this layer
+    pub world_content_transform: LayerToWorldTransform,
+
+    /// Transform for this layer, relative to parent scrollable layer.
+    pub local_transform: LayerToScrollTransform,
+
+    /// Pipeline that this layer belongs to
+    pub pipeline_id: PipelineId,
+
+    /// Child layers
+    pub children: Vec<ScrollLayerId>,
+}
+
+impl ClipScrollNode {
+    pub fn new(local_viewport_rect: &LayerRect,
+               content_size: LayerSize,
+               local_transform: &LayerToScrollTransform,
+               pipeline_id: PipelineId)
+               -> ClipScrollNode {
+        ClipScrollNode {
+            scrolling: ScrollingState::new(),
+            content_size: content_size,
+            local_viewport_rect: *local_viewport_rect,
+            combined_local_viewport_rect: *local_viewport_rect,
+            world_viewport_transform: LayerToWorldTransform::identity(),
+            world_content_transform: LayerToWorldTransform::identity(),
+            local_transform: *local_transform,
+            children: Vec::new(),
+            pipeline_id: pipeline_id,
+        }
+    }
+
+    pub fn add_child(&mut self, child: ScrollLayerId) {
+        self.children.push(child);
+    }
+
+    pub fn finalize(&mut self, scrolling: &ScrollingState) {
+        self.scrolling = *scrolling;
+    }
+
+    pub fn overscroll_amount(&self) -> LayerSize {
+        let scrollable_width = self.scrollable_width();
+        let overscroll_x = if self.scrolling.offset.x > 0.0 {
+            -self.scrolling.offset.x
+        } else if self.scrolling.offset.x < -scrollable_width {
+            -scrollable_width - self.scrolling.offset.x
+        } else {
+            0.0
+        };
+
+        let scrollable_height = self.scrollable_height();
+        let overscroll_y = if self.scrolling.offset.y > 0.0 {
+            -self.scrolling.offset.y
+        } else if self.scrolling.offset.y < -scrollable_height {
+            -scrollable_height - self.scrolling.offset.y
+        } else {
+            0.0
+        };
+
+        LayerSize::new(overscroll_x, overscroll_y)
+    }
+
+    pub fn set_scroll_origin(&mut self, origin: &LayerPoint) -> bool {
+        let scrollable_height = self.scrollable_height();
+        let scrollable_width = self.scrollable_width();
+        if scrollable_height <= 0. && scrollable_width <= 0. {
+            return false;
+        }
+
+        let new_offset = LayerPoint::new((-origin.x).max(-scrollable_width).min(0.0).round(),
+                                         (-origin.y).max(-scrollable_height).min(0.0).round());
+        if new_offset == self.scrolling.offset {
+            return false;
+        }
+
+        self.scrolling.offset = new_offset;
+        self.scrolling.bouncing_back = false;
+        self.scrolling.started_bouncing_back = false;
+        return true;
+    }
+
+    pub fn update_transform(&mut self,
+                            parent_world_transform: &ScrollToWorldTransform,
+                            parent_viewport_rect: &ScrollLayerRect) {
+        let inv_transform = match self.local_transform.inverse() {
+            Some(transform) => transform,
+            None => {
+                // If a transform function causes the current transformation matrix of an object
+                // to be non-invertible, the object and its content do not get displayed.
+                self.combined_local_viewport_rect = LayerRect::zero();
+                return;
+            }
+        };
+
+        let parent_viewport_rect_in_local_space = inv_transform.transform_rect(parent_viewport_rect)
+                                                               .translate(&-self.scrolling.offset);
+        let local_viewport_rect = self.local_viewport_rect.translate(&-self.scrolling.offset);
+        let viewport_rect = parent_viewport_rect_in_local_space.intersection(&local_viewport_rect)
+                                                               .unwrap_or(LayerRect::zero());
+
+        self.combined_local_viewport_rect = viewport_rect;
+        self.world_viewport_transform = parent_world_transform.pre_mul(&self.local_transform);
+        self.world_content_transform = self.world_viewport_transform
+                                                     .pre_translated(self.scrolling.offset.x,
+                                                                     self.scrolling.offset.y,
+                                                                     0.0);
+    }
+
+    pub fn scrollable_height(&self) -> f32 {
+        self.content_size.height - self.local_viewport_rect.size.height
+    }
+
+    pub fn scrollable_width(&self) -> f32 {
+        self.content_size.width - self.local_viewport_rect.size.width
+    }
+
+    pub fn scroll(&mut self, scroll_location: ScrollLocation, phase: ScrollEventPhase) -> bool {
+        if self.scrolling.started_bouncing_back && phase == ScrollEventPhase::Move(false) {
+            return false;
+        }
+
+        let mut delta = match scroll_location {
+            ScrollLocation::Delta(delta) => delta,
+            ScrollLocation::Start => {
+                if self.scrolling.offset.y.round() >= 0.0 {
+                    // Nothing to do on this layer.
+                    return false;
+                }
+
+                self.scrolling.offset.y = 0.0;
+                return true;
+            },
+            ScrollLocation::End => {
+                let end_pos = self.local_viewport_rect.size.height - self.content_size.height;
+
+                if self.scrolling.offset.y.round() <= end_pos {
+                    // Nothing to do on this layer.
+                    return false;
+                }
+
+                self.scrolling.offset.y = end_pos;
+                return true;
+            }
+        };
+
+        let overscroll_amount = self.overscroll_amount();
+        let overscrolling = CAN_OVERSCROLL && (overscroll_amount.width != 0.0 ||
+                                               overscroll_amount.height != 0.0);
+        if overscrolling {
+            if overscroll_amount.width != 0.0 {
+                delta.x /= overscroll_amount.width.abs()
+            }
+            if overscroll_amount.height != 0.0 {
+                delta.y /= overscroll_amount.height.abs()
+            }
+        }
+
+        let scrollable_width = self.scrollable_width();
+        let scrollable_height = self.scrollable_height();
+        let is_unscrollable = scrollable_width <= 0. && scrollable_height <= 0.;
+        let original_layer_scroll_offset = self.scrolling.offset;
+
+        if scrollable_width > 0. {
+            self.scrolling.offset.x = self.scrolling.offset.x + delta.x;
+            if is_unscrollable || !CAN_OVERSCROLL {
+                self.scrolling.offset.x =
+                    self.scrolling.offset.x.min(0.0).max(-scrollable_width).round();
+            }
+        }
+
+        if scrollable_height > 0. {
+            self.scrolling.offset.y = self.scrolling.offset.y + delta.y;
+            if is_unscrollable || !CAN_OVERSCROLL {
+                self.scrolling.offset.y =
+                    self.scrolling.offset.y.min(0.0).max(-scrollable_height).round();
+            }
+        }
+
+        if phase == ScrollEventPhase::Start || phase == ScrollEventPhase::Move(true) {
+            self.scrolling.started_bouncing_back = false
+        } else if overscrolling &&
+                ((delta.x < 1.0 && delta.y < 1.0) || phase == ScrollEventPhase::End) {
+            self.scrolling.started_bouncing_back = true;
+            self.scrolling.bouncing_back = true
+        }
+
+        if CAN_OVERSCROLL {
+            self.stretch_overscroll_spring();
+        }
+
+        self.scrolling.offset != original_layer_scroll_offset ||
+            self.scrolling.started_bouncing_back
+    }
+
+    pub fn stretch_overscroll_spring(&mut self) {
+        let overscroll_amount = self.overscroll_amount();
+        self.scrolling.spring.coords(self.scrolling.offset,
+                                     self.scrolling.offset,
+                                     self.scrolling.offset + overscroll_amount);
+    }
+
+    pub fn tick_scrolling_bounce_animation(&mut self) {
+        let finished = self.scrolling.spring.animate();
+        self.scrolling.offset = self.scrolling.spring.current();
+        if finished {
+            self.scrolling.bouncing_back = false
+        }
+    }
+
+    pub fn ray_intersects_node(&self, cursor: &WorldPoint) -> bool {
+        let inv = self.world_viewport_transform.inverse().unwrap();
+        let z0 = -10000.0;
+        let z1 =  10000.0;
+
+        let p0 = inv.transform_point4d(&WorldPoint4D::new(cursor.x, cursor.y, z0, 1.0));
+        let p0 = Point3D::new(p0.x / p0.w,
+                              p0.y / p0.w,
+                              p0.z / p0.w);
+        let p1 = inv.transform_point4d(&WorldPoint4D::new(cursor.x, cursor.y, z1, 1.0));
+        let p1 = Point3D::new(p1.x / p1.w,
+                              p1.y / p1.w,
+                              p1.z / p1.w);
+
+        if self.scrollable_width() <= 0. && self.scrollable_height() <= 0. {
+            return false;
+        }
+        ray_intersects_rect(p0, p1, self.local_viewport_rect.to_untyped())
+    }
+}
+
+#[derive(Copy, Clone)]
+pub struct ScrollingState {
+    pub offset: LayerPoint,
+    pub spring: Spring,
+    pub started_bouncing_back: bool,
+    pub bouncing_back: bool,
+    pub should_handoff_scroll: bool
+}
+
+impl ScrollingState {
+    pub fn new() -> ScrollingState {
+        ScrollingState {
+            offset: LayerPoint::zero(),
+            spring: Spring::at(LayerPoint::zero(), STIFFNESS, DAMPING),
+            started_bouncing_back: false,
+            bouncing_back: false,
+            should_handoff_scroll: false
+        }
+    }
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/src/clip_scroll_tree.rs
@@ -0,0 +1,394 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use fnv::FnvHasher;
+use clip_scroll_node::{ClipScrollNode, ScrollingState};
+use std::collections::{HashMap, HashSet};
+use std::hash::BuildHasherDefault;
+use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform, PipelineId};
+use webrender_traits::{ScrollEventPhase, ScrollLayerId, ScrollLayerInfo, ScrollLayerPixel};
+use webrender_traits::{ScrollLayerRect, ScrollLayerState, ScrollLocation, ScrollToWorldTransform};
+use webrender_traits::{ServoScrollRootId, WorldPoint, as_scroll_parent_rect};
+
+pub type ScrollStates = HashMap<ScrollLayerId, ScrollingState, BuildHasherDefault<FnvHasher>>;
+
+pub struct ClipScrollTree {
+    pub nodes: HashMap<ScrollLayerId, ClipScrollNode, BuildHasherDefault<FnvHasher>>,
+    pub pending_scroll_offsets: HashMap<(PipelineId, ServoScrollRootId), LayerPoint>,
+
+    /// The ScrollLayerId of the currently scrolling node. Used to allow the same
+    /// node to scroll even if a touch operation leaves the boundaries of that node.
+    pub current_scroll_layer_id: Option<ScrollLayerId>,
+
+    /// The current reference frame id, used for giving a unique id to all new
+    /// reference frames. The ClipScrollTree increments this by one every time a
+    /// reference frame is created.
+    current_reference_frame_id: usize,
+
+    /// The root reference frame, which is the true root of the ClipScrollTree. Initially
+    /// this ID is not valid, which is indicated by ```node``` being empty.
+    pub root_reference_frame_id: ScrollLayerId,
+
+    /// The root scroll node which is the first child of the root reference frame.
+    /// Initially this ID is not valid, which is indicated by ```nodes``` being empty.
+    pub topmost_scroll_layer_id: ScrollLayerId,
+
+    /// A set of pipelines which should be discarded the next time this
+    /// tree is drained.
+    pub pipelines_to_discard: HashSet<PipelineId>,
+}
+
+impl ClipScrollTree {
+    pub fn new() -> ClipScrollTree {
+        let dummy_pipeline = PipelineId(0, 0);
+        ClipScrollTree {
+            nodes: HashMap::with_hasher(Default::default()),
+            pending_scroll_offsets: HashMap::new(),
+            current_scroll_layer_id: None,
+            root_reference_frame_id: ScrollLayerId::root_reference_frame(dummy_pipeline),
+            topmost_scroll_layer_id: ScrollLayerId::root_scroll_layer(dummy_pipeline),
+            current_reference_frame_id: 1,
+            pipelines_to_discard: HashSet::new(),
+        }
+    }
+
+    pub fn root_reference_frame_id(&self) -> ScrollLayerId {
+        // TODO(mrobinson): We should eventually make this impossible to misuse.
+        debug_assert!(!self.nodes.is_empty());
+        debug_assert!(self.nodes.contains_key(&self.root_reference_frame_id));
+        self.root_reference_frame_id
+    }
+
+    pub fn topmost_scroll_layer_id(&self) -> ScrollLayerId {
+        // TODO(mrobinson): We should eventually make this impossible to misuse.
+        debug_assert!(!self.nodes.is_empty());
+        debug_assert!(self.nodes.contains_key(&self.topmost_scroll_layer_id));
+        self.topmost_scroll_layer_id
+    }
+
+    pub fn establish_root(&mut self,
+                          pipeline_id: PipelineId,
+                          viewport_size: &LayerSize,
+                          content_size: &LayerSize) {
+        debug_assert!(self.nodes.is_empty());
+
+        let identity = LayerToScrollTransform::identity();
+        let viewport = LayerRect::new(LayerPoint::zero(), *viewport_size);
+
+        let root_reference_frame_id = ScrollLayerId::root_reference_frame(pipeline_id);
+        self.root_reference_frame_id = root_reference_frame_id;
+        let reference_frame = ClipScrollNode::new(&viewport, viewport.size, &identity, pipeline_id);
+        self.nodes.insert(self.root_reference_frame_id, reference_frame);
+
+        let scroll_node = ClipScrollNode::new(&viewport, *content_size, &identity, pipeline_id);
+        let topmost_scroll_layer_id = ScrollLayerId::root_scroll_layer(pipeline_id);
+        self.topmost_scroll_layer_id = topmost_scroll_layer_id;
+        self.add_node(scroll_node, topmost_scroll_layer_id, root_reference_frame_id);
+    }
+
+    pub fn collect_nodes_bouncing_back(&self)
+                                       -> HashSet<ScrollLayerId, BuildHasherDefault<FnvHasher>> {
+        let mut nodes_bouncing_back = HashSet::with_hasher(Default::default());
+        for (scroll_layer_id, node) in self.nodes.iter() {
+            if node.scrolling.bouncing_back {
+                nodes_bouncing_back.insert(*scroll_layer_id);
+            }
+        }
+        nodes_bouncing_back
+    }
+
+    fn find_scrolling_node_at_point_in_node(&self,
+                                            cursor: &WorldPoint,
+                                            scroll_layer_id: ScrollLayerId)
+                                            -> Option<ScrollLayerId> {
+        self.nodes.get(&scroll_layer_id).and_then(|node| {
+            for child_layer_id in node.children.iter().rev() {
+            if let Some(layer_id) =
+                self.find_scrolling_node_at_point_in_node(cursor, *child_layer_id) {
+                    return Some(layer_id);
+                }
+            }
+
+            if let ScrollLayerInfo::ReferenceFrame(_) = scroll_layer_id.info {
+                return None;
+            }
+
+            if node.ray_intersects_node(cursor) {
+                Some(scroll_layer_id)
+            } else {
+                None
+            }
+        })
+    }
+
+    pub fn find_scrolling_node_at_point(&self, cursor: &WorldPoint) -> ScrollLayerId {
+        self.find_scrolling_node_at_point_in_node(cursor, self.root_reference_frame_id())
+            .unwrap_or(self.topmost_scroll_layer_id())
+    }
+
+    pub fn get_scroll_node_state(&self) -> Vec<ScrollLayerState> {
+        let mut result = vec![];
+        for (scroll_layer_id, scroll_node) in self.nodes.iter() {
+            match scroll_layer_id.info {
+                ScrollLayerInfo::Scrollable(_, servo_scroll_root_id) => {
+                    result.push(ScrollLayerState {
+                        pipeline_id: scroll_node.pipeline_id,
+                        scroll_root_id: servo_scroll_root_id,
+                        scroll_offset: scroll_node.scrolling.offset,
+                    })
+                }
+                ScrollLayerInfo::ReferenceFrame(..) => {}
+            }
+        }
+        result
+    }
+
+    pub fn drain(&mut self) -> ScrollStates {
+        self.current_reference_frame_id = 1;
+
+        let mut scroll_states = HashMap::with_hasher(Default::default());
+        for (layer_id, old_node) in &mut self.nodes.drain() {
+            if !self.pipelines_to_discard.contains(&layer_id.pipeline_id) {
+                scroll_states.insert(layer_id, old_node.scrolling);
+            }
+        }
+
+        self.pipelines_to_discard.clear();
+        scroll_states
+    }
+
+    pub fn scroll_nodes(&mut self,
+                        origin: LayerPoint,
+                        pipeline_id: PipelineId,
+                        scroll_root_id: ServoScrollRootId)
+                        -> bool {
+        if self.nodes.is_empty() {
+            self.pending_scroll_offsets.insert((pipeline_id, scroll_root_id), origin);
+            return false;
+        }
+
+        let origin = LayerPoint::new(origin.x.max(0.0), origin.y.max(0.0));
+
+        let mut scrolled_a_node = false;
+        let mut found_node = false;
+        for (layer_id, node) in self.nodes.iter_mut() {
+            if layer_id.pipeline_id != pipeline_id {
+                continue;
+            }
+
+            match layer_id.info {
+                ScrollLayerInfo::Scrollable(_, id) if id != scroll_root_id => continue,
+                ScrollLayerInfo::ReferenceFrame(..) => continue,
+                ScrollLayerInfo::Scrollable(..) => {}
+            }
+
+            found_node = true;
+            scrolled_a_node |= node.set_scroll_origin(&origin);
+        }
+
+        if !found_node {
+            self.pending_scroll_offsets.insert((pipeline_id, scroll_root_id), origin);
+        }
+
+        scrolled_a_node
+    }
+
+    pub fn scroll(&mut self,
+                  scroll_location: ScrollLocation,
+                  cursor: WorldPoint,
+                  phase: ScrollEventPhase)
+                  -> bool {
+        if self.nodes.is_empty() {
+            return false;
+        }
+
+        let scroll_layer_id = match (
+            phase,
+            self.find_scrolling_node_at_point(&cursor),
+            self.current_scroll_layer_id) {
+            (ScrollEventPhase::Start, scroll_node_at_point_id, _) => {
+                self.current_scroll_layer_id = Some(scroll_node_at_point_id);
+                scroll_node_at_point_id
+            },
+            (_, scroll_node_at_point_id, Some(cached_scroll_layer_id)) => {
+                let scroll_layer_id = match self.nodes.get(&cached_scroll_layer_id) {
+                    Some(_) => cached_scroll_layer_id,
+                    None => {
+                        self.current_scroll_layer_id = Some(scroll_node_at_point_id);
+                        scroll_node_at_point_id
+                    },
+                };
+                scroll_layer_id
+            },
+            (_, _, None) => return false,
+        };
+
+        let topmost_scroll_layer_id = self.topmost_scroll_layer_id();
+        let non_root_overscroll = if scroll_layer_id != topmost_scroll_layer_id {
+            // true if the current node is overscrolling,
+            // and it is not the root scroll node.
+            let child_node = self.nodes.get(&scroll_layer_id).unwrap();
+            let overscroll_amount = child_node.overscroll_amount();
+            overscroll_amount.width != 0.0 || overscroll_amount.height != 0.0
+        } else {
+            false
+        };
+
+        let switch_node = match phase {
+            ScrollEventPhase::Start => {
+                // if this is a new gesture, we do not switch node,
+                // however we do save the state of non_root_overscroll,
+                // for use in the subsequent Move phase.
+                let mut current_node = self.nodes.get_mut(&scroll_layer_id).unwrap();
+                current_node.scrolling.should_handoff_scroll = non_root_overscroll;
+                false
+            },
+            ScrollEventPhase::Move(_) => {
+                // Switch node if movement originated in a new gesture,
+                // from a non root node in overscroll.
+                let current_node = self.nodes.get_mut(&scroll_layer_id).unwrap();
+                current_node.scrolling.should_handoff_scroll && non_root_overscroll
+            },
+            ScrollEventPhase::End => {
+                // clean-up when gesture ends.
+                let mut current_node = self.nodes.get_mut(&scroll_layer_id).unwrap();
+                current_node.scrolling.should_handoff_scroll = false;
+                false
+            },
+        };
+
+        let scroll_node_info = if switch_node {
+            topmost_scroll_layer_id.info
+        } else {
+            scroll_layer_id.info
+        };
+
+        let scroll_root_id = match scroll_node_info {
+             ScrollLayerInfo::Scrollable(_, scroll_root_id) => scroll_root_id,
+             _ => unreachable!("Tried to scroll a reference frame."),
+
+        };
+
+        let mut scrolled_a_node = false;
+        for (layer_id, node) in self.nodes.iter_mut() {
+            if layer_id.pipeline_id != scroll_layer_id.pipeline_id {
+                continue;
+            }
+
+            match layer_id.info {
+                ScrollLayerInfo::Scrollable(_, id) if id != scroll_root_id => continue,
+                ScrollLayerInfo::ReferenceFrame(..) => continue,
+                _ => {}
+            }
+
+            let scrolled_this_node = node.scroll(scroll_location, phase);
+            scrolled_a_node = scrolled_a_node || scrolled_this_node;
+        }
+        scrolled_a_node
+    }
+
+    pub fn update_all_node_transforms(&mut self) {
+        if self.nodes.is_empty() {
+            return;
+        }
+
+        let root_reference_frame_id = self.root_reference_frame_id();
+        let root_viewport = self.nodes[&root_reference_frame_id].local_viewport_rect;
+        self.update_node_transform(root_reference_frame_id,
+                                    &ScrollToWorldTransform::identity(),
+                                    &as_scroll_parent_rect(&root_viewport));
+    }
+
+    fn update_node_transform(&mut self,
+                             layer_id: ScrollLayerId,
+                             parent_world_transform: &ScrollToWorldTransform,
+                             parent_viewport_rect: &ScrollLayerRect) {
+        // TODO(gw): This is an ugly borrow check workaround to clone these.
+        //           Restructure this to avoid the clones!
+        let (node_transform_for_children, viewport_rect, node_children) = {
+            match self.nodes.get_mut(&layer_id) {
+                Some(node) => {
+                    node.update_transform(parent_world_transform, parent_viewport_rect);
+
+                    (node.world_content_transform.with_source::<ScrollLayerPixel>(),
+                     as_scroll_parent_rect(&node.combined_local_viewport_rect),
+                     node.children.clone())
+                }
+                None => return,
+            }
+        };
+
+        for child_layer_id in node_children {
+            self.update_node_transform(child_layer_id,
+                                       &node_transform_for_children,
+                                       &viewport_rect);
+        }
+    }
+
+    pub fn tick_scrolling_bounce_animations(&mut self) {
+        for (_, node) in &mut self.nodes {
+            node.tick_scrolling_bounce_animation()
+        }
+    }
+
+    pub fn finalize_and_apply_pending_scroll_offsets(&mut self, old_states: ScrollStates) {
+        // TODO(gw): These are all independent - can be run through thread pool if it shows up
+        // in the profile!
+        for (scroll_layer_id, node) in &mut self.nodes {
+            let scrolling_state = match old_states.get(&scroll_layer_id) {
+                Some(old_scrolling_state) => *old_scrolling_state,
+                None => ScrollingState::new(),
+            };
+
+            node.finalize(&scrolling_state);
+
+            let scroll_root_id = match scroll_layer_id.info {
+                ScrollLayerInfo::Scrollable(_, scroll_root_id) => scroll_root_id,
+                _ => continue,
+            };
+
+
+            let pipeline_id = scroll_layer_id.pipeline_id;
+            if let Some(pending_offset) =
+                self.pending_scroll_offsets.remove(&(pipeline_id, scroll_root_id)) {
+                node.set_scroll_origin(&pending_offset);
+            }
+        }
+
+    }
+
+    pub fn add_reference_frame(&mut self,
+                               rect: LayerRect,
+                               transform: LayerToScrollTransform,
+                               pipeline_id: PipelineId,
+                               parent_id: ScrollLayerId) -> ScrollLayerId {
+        let reference_frame_id = ScrollLayerId {
+            pipeline_id: pipeline_id,
+            info: ScrollLayerInfo::ReferenceFrame(self.current_reference_frame_id),
+        };
+        self.current_reference_frame_id += 1;
+
+        let node = ClipScrollNode::new(&rect, rect.size, &transform, pipeline_id);
+        self.add_node(node, reference_frame_id, parent_id);
+        reference_frame_id
+    }
+
+    pub fn add_node(&mut self, node: ClipScrollNode, id: ScrollLayerId, parent_id: ScrollLayerId) {
+        debug_assert!(!self.nodes.contains_key(&id));
+        self.nodes.insert(id, node);
+
+        debug_assert!(parent_id != id);
+        self.nodes.get_mut(&parent_id).unwrap().add_child(id);
+    }
+
+    pub fn discard_frame_state_for_pipeline(&mut self, pipeline_id: PipelineId) {
+        self.pipelines_to_discard.insert(pipeline_id);
+
+        match self.current_scroll_layer_id {
+            Some(id) if id.pipeline_id == pipeline_id => self.current_scroll_layer_id = None,
+            _ => {}
+        }
+    }
+}
+
--- a/gfx/webrender/src/device.rs
+++ b/gfx/webrender/src/device.rs
@@ -37,22 +37,16 @@ const GL_FORMAT_BGRA: gl::GLuint = gl::B
 #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
 const SHADER_VERSION: &'static str = "#version 150\n";
 
 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
 const SHADER_VERSION: &'static str = "#version 300 es\n";
 
 static SHADER_PREAMBLE: &'static str = "shared";
 
-lazy_static! {
-    pub static ref MAX_TEXTURE_SIZE: gl::GLint = {
-        gl::get_integer_v(gl::MAX_TEXTURE_SIZE)
-    };
-}
-
 #[repr(u32)]
 pub enum DepthFunction {
     Less = gl::LESS,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub enum TextureTarget {
     Default,
@@ -820,16 +814,18 @@ pub struct Device {
 
     // misc.
     shader_preamble: String,
     //file_watcher: FileWatcherThread,
 
     // Used on android only
     #[allow(dead_code)]
     next_vao_id: gl::GLuint,
+
+    max_texture_size: u32,
 }
 
 impl Device {
     pub fn new(resource_override_path: Option<PathBuf>,
                _file_changed_handler: Box<FileWatcherHandler>) -> Device {
         //let file_watcher = FileWatcherThread::new(file_changed_handler);
 
         let shader_preamble = get_shader_source(SHADER_PREAMBLE, &resource_override_path);
@@ -858,19 +854,25 @@ impl Device {
             textures: HashMap::with_hasher(Default::default()),
             programs: HashMap::with_hasher(Default::default()),
             vaos: HashMap::with_hasher(Default::default()),
 
             shader_preamble: shader_preamble,
 
             next_vao_id: 1,
             //file_watcher: file_watcher,
+
+            max_texture_size: gl::get_integer_v(gl::MAX_TEXTURE_SIZE) as u32
         }
     }
 
+    pub fn max_texture_size(&self) -> u32 {
+        self.max_texture_size
+    }
+
     pub fn get_capabilities(&self) -> &Capabilities {
         &self.capabilities
     }
 
     pub fn compile_shader(name: &str,
                           source_str: &str,
                           shader_type: gl::GLenum,
                           shader_preamble: &[String])
--- a/gfx/webrender/src/frame.rs
+++ b/gfx/webrender/src/frame.rs
@@ -3,20 +3,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use app_units::Au;
 use fnv::FnvHasher;
 use internal_types::{ANGLE_FLOAT_TO_FIXED, AxisDirection};
 use internal_types::{LowLevelFilterOp};
 use internal_types::{RendererFrame};
 use frame_builder::{FrameBuilder, FrameBuilderConfig};
-use layer::Layer;
+use clip_scroll_node::ClipScrollNode;
 use resource_cache::ResourceCache;
 use scene::{Scene, SceneProperties};
-use scroll_tree::{ScrollTree, ScrollStates};
+use clip_scroll_tree::{ClipScrollTree, ScrollStates};
 use std::collections::HashMap;
 use std::hash::BuildHasherDefault;
 use tiling::{AuxiliaryListsMap, CompositeOps, PrimitiveFlags};
 use webrender_traits::{AuxiliaryLists, ClipRegion, ColorF, DisplayItem, Epoch, FilterOp};
 use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform, LayoutTransform};
 use webrender_traits::{MixBlendMode, PipelineId, ScrollEventPhase, ScrollLayerId, ScrollLayerState};
 use webrender_traits::{ScrollLocation, ScrollPolicy, ServoScrollRootId, SpecificDisplayItem};
 use webrender_traits::{StackingContext, WorldPoint};
@@ -28,17 +28,17 @@ static DEFAULT_SCROLLBAR_COLOR: ColorF =
 
 struct FlattenContext<'a> {
     scene: &'a Scene,
     builder: &'a mut FrameBuilder,
 }
 
 // TODO: doc
 pub struct Frame {
-    pub scroll_tree: ScrollTree,
+    pub clip_scroll_tree: ClipScrollTree,
     pub pipeline_epoch_map: HashMap<PipelineId, Epoch, BuildHasherDefault<FnvHasher>>,
     pub pipeline_auxiliary_lists: AuxiliaryListsMap,
     id: FrameId,
     frame_builder_config: FrameBuilderConfig,
     frame_builder: Option<FrameBuilder>,
 }
 
 trait DisplayListHelpers {
@@ -175,60 +175,60 @@ impl<'a> Iterator for DisplayListTravers
     }
 }
 
 impl Frame {
     pub fn new(config: FrameBuilderConfig) -> Frame {
         Frame {
             pipeline_epoch_map: HashMap::with_hasher(Default::default()),
             pipeline_auxiliary_lists: HashMap::with_hasher(Default::default()),
-            scroll_tree: ScrollTree::new(),
+            clip_scroll_tree: ClipScrollTree::new(),
             id: FrameId(0),
             frame_builder: None,
             frame_builder_config: config,
         }
     }
 
     pub fn reset(&mut self) -> ScrollStates {
         self.pipeline_epoch_map.clear();
 
         // Advance to the next frame.
         self.id.0 += 1;
 
-        self.scroll_tree.drain()
+        self.clip_scroll_tree.drain()
     }
 
-    pub fn get_scroll_layer_state(&self) -> Vec<ScrollLayerState> {
-        self.scroll_tree.get_scroll_layer_state()
+    pub fn get_scroll_node_state(&self) -> Vec<ScrollLayerState> {
+        self.clip_scroll_tree.get_scroll_node_state()
     }
 
-    /// Returns true if any layers actually changed position or false otherwise.
-    pub fn scroll_layers(&mut self,
-                         origin: LayerPoint,
-                         pipeline_id: PipelineId,
-                         scroll_root_id: ServoScrollRootId)
-                          -> bool {
-        self.scroll_tree.scroll_layers(origin, pipeline_id, scroll_root_id)
+    /// Returns true if any nodes actually changed position or false otherwise.
+    pub fn scroll_nodes(&mut self,
+                        origin: LayerPoint,
+                        pipeline_id: PipelineId,
+                        scroll_root_id: ServoScrollRootId)
+                         -> bool {
+        self.clip_scroll_tree.scroll_nodes(origin, pipeline_id, scroll_root_id)
     }
 
-    /// Returns true if any layers actually changed position or false otherwise.
+    /// Returns true if any nodes actually changed position or false otherwise.
     pub fn scroll(&mut self,
                   scroll_location: ScrollLocation,
                   cursor: WorldPoint,
                   phase: ScrollEventPhase)
                   -> bool {
-        self.scroll_tree.scroll(scroll_location, cursor, phase,)
+        self.clip_scroll_tree.scroll(scroll_location, cursor, phase,)
     }
 
     pub fn tick_scrolling_bounce_animations(&mut self) {
-        self.scroll_tree.tick_scrolling_bounce_animations();
+        self.clip_scroll_tree.tick_scrolling_bounce_animations();
     }
 
     pub fn discard_frame_state_for_pipeline(&mut self, pipeline_id: PipelineId) {
-        self.scroll_tree.discard_frame_state_for_pipeline(pipeline_id);
+        self.clip_scroll_tree.discard_frame_state_for_pipeline(pipeline_id);
     }
 
     pub fn create(&mut self, scene: &Scene) {
         let root_pipeline_id = match scene.root_pipeline_id {
             Some(root_pipeline_id) => root_pipeline_id,
             None => return,
         };
 
@@ -251,19 +251,19 @@ impl Frame {
         let (root_stacking_context, root_clip) = match display_list.starting_stacking_context() {
             Some(some) => some,
             None => {
                 warn!("Pipeline display list does not start with a stacking context.");
                 return;
             }
         };
 
-        self.scroll_tree.establish_root(root_pipeline_id,
-                                        &root_pipeline.viewport_size,
-                                        &root_clip.main.size);
+        self.clip_scroll_tree.establish_root(root_pipeline_id,
+                                             &root_pipeline.viewport_size,
+                                             &root_clip.main.size);
 
         let background_color = root_pipeline.background_color.and_then(|color| {
             if color.a > 0.0 {
                 Some(color)
             } else {
                 None
             }
         });
@@ -274,47 +274,47 @@ impl Frame {
 
         {
             let mut context = FlattenContext {
                 scene: scene,
                 builder: &mut frame_builder,
             };
 
             let mut traversal = DisplayListTraversal::new_skipping_first(display_list);
-            let reference_frame_id = self.scroll_tree.root_reference_frame_id();
-            let topmost_scroll_layer_id = self.scroll_tree.topmost_scroll_layer_id();
+            let reference_frame_id = self.clip_scroll_tree.root_reference_frame_id();
+            let topmost_scroll_layer_id = self.clip_scroll_tree.topmost_scroll_layer_id();
             debug_assert!(reference_frame_id != topmost_scroll_layer_id);
 
             let viewport_rect = LayerRect::new(LayerPoint::zero(), root_pipeline.viewport_size);
             let clip = ClipRegion::simple(&viewport_rect);
-            context.builder.push_scroll_layer(reference_frame_id,
-                                              &clip,
-                                              &LayerPoint::zero(),
-                                              &root_pipeline.viewport_size);
-            context.builder.push_scroll_layer(topmost_scroll_layer_id,
-                                              &clip,
-                                              &LayerPoint::zero(),
-                                              &root_clip.main.size);
+            context.builder.push_clip_scroll_node(reference_frame_id,
+                                                  &clip,
+                                                  &LayerPoint::zero(),
+                                                  &root_pipeline.viewport_size);
+            context.builder.push_clip_scroll_node(topmost_scroll_layer_id,
+                                                  &clip,
+                                                  &LayerPoint::zero(),
+                                                  &root_clip.main.size);
 
             self.flatten_stacking_context(&mut traversal,
                                           root_pipeline_id,
                                           &mut context,
                                           reference_frame_id,
                                           topmost_scroll_layer_id,
                                           LayerToScrollTransform::identity(),
                                           0,
                                           &root_stacking_context,
                                           root_clip);
 
-            context.builder.pop_scroll_layer();
-            context.builder.pop_scroll_layer();
+            context.builder.pop_clip_scroll_node();
+            context.builder.pop_clip_scroll_node();
         }
 
         self.frame_builder = Some(frame_builder);
-        self.scroll_tree.finalize_and_apply_pending_scroll_offsets(old_scrolling_states);
+        self.clip_scroll_tree.finalize_and_apply_pending_scroll_offsets(old_scrolling_states);
     }
 
     fn flatten_scroll_layer<'a>(&mut self,
                                 traversal: &mut DisplayListTraversal<'a>,
                                 pipeline_id: PipelineId,
                                 context: &mut FlattenContext,
                                 current_reference_frame_id: ScrollLayerId,
                                 parent_scroll_layer_id: ScrollLayerId,
@@ -325,32 +325,35 @@ impl Frame {
                                 new_scroll_layer_id: ScrollLayerId) {
         // Avoid doing unnecessary work for empty stacking contexts.
         if traversal.current_stacking_context_empty() {
             traversal.skip_current_stacking_context();
             return;
         }
 
         let clip_rect = clip.main;
-        let layer = Layer::new(&clip_rect, *content_size, &layer_relative_transform, pipeline_id);
-        self.scroll_tree.add_layer(layer, new_scroll_layer_id, parent_scroll_layer_id);
-        context.builder.push_scroll_layer(new_scroll_layer_id,
-                                          clip,
-                                          &clip_rect.origin,
-                                          &content_size);
+        let node = ClipScrollNode::new(&clip_rect,
+                                       *content_size,
+                                       &layer_relative_transform,
+                                       pipeline_id);
+        self.clip_scroll_tree.add_node(node, new_scroll_layer_id, parent_scroll_layer_id);
+        context.builder.push_clip_scroll_node(new_scroll_layer_id,
+                                              clip,
+                                              &clip_rect.origin,
+                                              &content_size);
 
         self.flatten_items(traversal,
                            pipeline_id,
                            context,
                            current_reference_frame_id,
                            new_scroll_layer_id,
                            LayerToScrollTransform::identity(),
                            level);
 
-        context.builder.pop_scroll_layer();
+        context.builder.pop_clip_scroll_node();
     }
 
     fn flatten_stacking_context<'a>(&mut self,
                                     traversal: &mut DisplayListTraversal<'a>,
                                     pipeline_id: PipelineId,
                                     context: &mut FlattenContext,
                                     current_reference_frame_id: ScrollLayerId,
                                     current_scroll_layer_id: ScrollLayerId,
@@ -394,20 +397,20 @@ impl Frame {
             ScrollPolicy::Fixed => current_reference_frame_id,
             ScrollPolicy::Scrollable => current_scroll_layer_id,
         };
 
         // If we have a transformation, we establish a new reference frame. This means
         // that fixed position stacking contexts are positioned relative to us.
         if stacking_context_transform != LayoutTransform::identity() ||
            stacking_context.perspective != LayoutTransform::identity() {
-            scroll_layer_id = self.scroll_tree.add_reference_frame(clip_region.main,
-                                                                   transform,
-                                                                   pipeline_id,
-                                                                   scroll_layer_id);
+            scroll_layer_id = self.clip_scroll_tree.add_reference_frame(clip_region.main,
+                                                                        transform,
+                                                                        pipeline_id,
+                                                                        scroll_layer_id);
             reference_frame_id = scroll_layer_id;
             transform = LayerToScrollTransform::identity();
         }
 
         if level == 0 {
             if let Some(pipeline) = context.scene.pipeline_map.get(&pipeline_id) {
                 if let Some(bg_color) = pipeline.background_color {
 
@@ -415,17 +418,17 @@ impl Frame {
                     let no_clip = ClipRegion::simple(&clip_region.main);
                     context.builder.push_stacking_context(clip_region.main,
                                                           transform,
                                                           pipeline_id,
                                                           scroll_layer_id,
                                                           CompositeOps::empty());
 
                     //Note: we don't use the original clip region here,
-                    // it's already processed by the layer we just pushed.
+                    // it's already processed by the node we just pushed.
                     context.builder.add_solid_rectangle(&clip_region.main,
                                                         &no_clip,
                                                         &bg_color,
                                                         PrimitiveFlags::None);
 
                     context.builder.pop_stacking_context();
                 }
             }
@@ -447,17 +450,17 @@ impl Frame {
                            level);
 
         if level == 0 && self.frame_builder_config.enable_scrollbars {
             let scrollbar_rect = LayerRect::new(LayerPoint::zero(), LayerSize::new(10.0, 70.0));
             context.builder.add_solid_rectangle(
                 &scrollbar_rect,
                 &ClipRegion::simple(&scrollbar_rect),
                 &DEFAULT_SCROLLBAR_COLOR,
-                PrimitiveFlags::Scrollbar(self.scroll_tree.topmost_scroll_layer_id, 4.0));
+                PrimitiveFlags::Scrollbar(self.clip_scroll_tree.topmost_scroll_layer_id(), 4.0));
         }
 
         context.builder.pop_stacking_context();
     }
 
     fn flatten_iframe<'a>(&mut self,
                           pipeline_id: PipelineId,
                           bounds: &LayerRect,
@@ -486,52 +489,52 @@ impl Frame {
 
         self.pipeline_epoch_map.insert(pipeline_id, pipeline.epoch);
 
         let iframe_rect = LayerRect::new(LayerPoint::zero(), bounds.size);
         let transform = layer_relative_transform.pre_translated(bounds.origin.x,
                                                                 bounds.origin.y,
                                                                 0.0);
         let iframe_reference_frame_id =
-            self.scroll_tree.add_reference_frame(iframe_rect,
-                                                 transform,
-                                                 pipeline_id,
-                                                 current_scroll_layer_id);
+            self.clip_scroll_tree.add_reference_frame(iframe_rect,
+                                                      transform,
+                                                      pipeline_id,
+                                                      current_scroll_layer_id);
         let iframe_scroll_layer_id = ScrollLayerId::root_scroll_layer(pipeline_id);
-        let layer = Layer::new(&LayerRect::new(LayerPoint::zero(), iframe_rect.size),
-                               iframe_clip.main.size,
-                               &LayerToScrollTransform::identity(),
-                               pipeline_id);
-        self.scroll_tree.add_layer(layer.clone(),
-                                   iframe_scroll_layer_id,
-                                   iframe_reference_frame_id);
+        let node = ClipScrollNode::new(&LayerRect::new(LayerPoint::zero(), iframe_rect.size),
+                                       iframe_clip.main.size,
+                                       &LayerToScrollTransform::identity(),
+                                       pipeline_id);
+        self.clip_scroll_tree.add_node(node.clone(),
+                                       iframe_scroll_layer_id,
+                                       iframe_reference_frame_id);
 
-        context.builder.push_scroll_layer(iframe_reference_frame_id,
-                                          iframe_clip,
-                                          &LayerPoint::zero(),
-                                          &iframe_rect.size);
-        context.builder.push_scroll_layer(iframe_scroll_layer_id,
-                                          iframe_clip,
-                                          &LayerPoint::zero(),
-                                          &iframe_clip.main.size);
+        context.builder.push_clip_scroll_node(iframe_reference_frame_id,
+                                              iframe_clip,
+                                              &LayerPoint::zero(),
+                                              &iframe_rect.size);
+        context.builder.push_clip_scroll_node(iframe_scroll_layer_id,
+                                              iframe_clip,
+                                              &LayerPoint::zero(),
+                                              &iframe_clip.main.size);
 
         let mut traversal = DisplayListTraversal::new_skipping_first(display_list);
 
         self.flatten_stacking_context(&mut traversal,
                                       pipeline_id,
                                       context,
                                       iframe_reference_frame_id,
                                       iframe_scroll_layer_id,
                                       LayerToScrollTransform::identity(),
                                       0,
                                       &iframe_stacking_context,
                                       iframe_clip);
 
-        context.builder.pop_scroll_layer();
-        context.builder.pop_scroll_layer();
+        context.builder.pop_clip_scroll_node();
+        context.builder.pop_clip_scroll_node();
     }
 
     fn flatten_items<'a>(&mut self,
                          traversal: &mut DisplayListTraversal<'a>,
                          pipeline_id: PipelineId,
                          context: &mut FlattenContext,
                          current_reference_frame_id: ScrollLayerId,
                          current_scroll_layer_id: ScrollLayerId,
@@ -543,16 +546,17 @@ impl Frame {
                     context.builder.add_webgl_rectangle(item.rect,
                                                         &item.clip, info.context_id);
                 }
                 SpecificDisplayItem::Image(ref info) => {
                     context.builder.add_image(item.rect,
                                               &item.clip,
                                               &info.stretch_size,
                                               &info.tile_spacing,
+                                              None,
                                               info.image_key,
                                               info.image_rendering);
                 }
                 SpecificDisplayItem::YuvImage(ref info) => {
                     context.builder.add_yuv_image(item.rect,
                                                   &item.clip,
                                                   info.y_image_key,
                                                   info.u_image_key,
@@ -642,34 +646,34 @@ impl Frame {
         }
     }
 
     pub fn build(&mut self,
                  resource_cache: &mut ResourceCache,
                  auxiliary_lists_map: &AuxiliaryListsMap,
                  device_pixel_ratio: f32)
                  -> RendererFrame {
-        self.scroll_tree.update_all_layer_transforms();
+        self.clip_scroll_tree.update_all_node_transforms();
         let frame = self.build_frame(resource_cache,
                                      auxiliary_lists_map,
                                      device_pixel_ratio);
         resource_cache.expire_old_resources(self.id);
         frame
     }
 
     fn build_frame(&mut self,
                    resource_cache: &mut ResourceCache,
                    auxiliary_lists_map: &AuxiliaryListsMap,
                    device_pixel_ratio: f32) -> RendererFrame {
         let mut frame_builder = self.frame_builder.take();
         let frame = frame_builder.as_mut().map(|builder|
             builder.build(resource_cache,
                           self.id,
-                          &self.scroll_tree,
+                          &self.clip_scroll_tree,
                           auxiliary_lists_map,
                           device_pixel_ratio)
         );
         self.frame_builder = frame_builder;
 
-        let layers_bouncing_back = self.scroll_tree.collect_layers_bouncing_back();
-        RendererFrame::new(self.pipeline_epoch_map.clone(), layers_bouncing_back, frame)
+        let nodes_bouncing_back = self.clip_scroll_tree.collect_nodes_bouncing_back();
+        RendererFrame::new(self.pipeline_epoch_map.clone(), nodes_bouncing_back, frame)
     }
 }
--- a/gfx/webrender/src/frame_builder.rs
+++ b/gfx/webrender/src/frame_builder.rs
@@ -8,35 +8,83 @@ use frame::FrameId;
 use gpu_store::GpuStoreAddress;
 use internal_types::{HardwareCompositeOp, SourceTexture};
 use mask_cache::{ClipSource, MaskCacheInfo};
 use prim_store::{BorderPrimitiveCpu, BorderPrimitiveGpu, BoxShadowPrimitiveGpu};
 use prim_store::{GradientPrimitiveCpu, GradientPrimitiveGpu, ImagePrimitiveCpu, ImagePrimitiveGpu};
 use prim_store::{ImagePrimitiveKind, PrimitiveContainer, PrimitiveGeometry, PrimitiveIndex};
 use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu, RadialGradientPrimitiveGpu};
 use prim_store::{RectanglePrimitive, TextRunPrimitiveCpu, TextRunPrimitiveGpu};
-use prim_store::{YuvImagePrimitiveCpu, YuvImagePrimitiveGpu};
+use prim_store::{TexelRect, YuvImagePrimitiveCpu, YuvImagePrimitiveGpu};
 use profiler::FrameProfileCounters;
 use render_task::{AlphaRenderItem, MaskCacheKey, MaskResult, RenderTask, RenderTaskIndex};
 use render_task::RenderTaskLocation;
 use resource_cache::ResourceCache;
-use scroll_tree::ScrollTree;
+use clip_scroll_tree::ClipScrollTree;
 use std::{cmp, f32, i32, mem, usize};
-use tiling::{AuxiliaryListsMap, CompositeOps, Frame, PackedLayer, PackedLayerIndex};
-use tiling::{PrimitiveFlags, PrimitiveRunCmd, RenderPass, RenderTargetContext};
-use tiling::{RenderTaskCollection, ScrollbarPrimitive, ScrollLayer, ScrollLayerIndex};
-use tiling::{StackingContext, StackingContextIndex};
+use tiling::{AuxiliaryListsMap, ClipScrollGroup, ClipScrollGroupIndex, CompositeOps, Frame};
+use tiling::{PackedLayer, PackedLayerIndex, PrimitiveFlags, PrimitiveRunCmd, RenderPass};
+use tiling::{RenderTargetContext, RenderTaskCollection, ScrollbarPrimitive, ScrollLayer};
+use tiling::{ScrollLayerIndex, StackingContext, StackingContextIndex};
 use util::{self, pack_as_float, rect_from_points_f, subtract_rect, TransformedRect};
-use util::TransformedRectKind;
-use webrender_traits::{as_scroll_parent_rect, BorderDisplayItem, BorderSide, BorderStyle};
+use util::{RectHelpers, TransformedRectKind};
+use webrender_traits::{as_scroll_parent_rect, BorderDetails, BorderDisplayItem, BorderSide, BorderStyle};
 use webrender_traits::{BoxShadowClipMode, ClipRegion, ColorF, device_length, DeviceIntPoint};
 use webrender_traits::{DeviceIntRect, DeviceIntSize, DeviceUintSize, ExtendMode, FontKey};
 use webrender_traits::{FontRenderMode, GlyphOptions, ImageKey, ImageRendering, ItemRange};
 use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform, PipelineId};
-use webrender_traits::{ScrollLayerId, ScrollLayerPixel, WebGLContextId, YuvColorSpace};
+use webrender_traits::{RepeatMode, ScrollLayerId, ScrollLayerPixel, WebGLContextId, YuvColorSpace};
+
+#[derive(Debug, Clone)]
+struct ImageBorderSegment {
+    geom_rect: LayerRect,
+    sub_rect: TexelRect,
+    stretch_size: LayerSize,
+    tile_spacing: LayerSize,
+}
+
+impl ImageBorderSegment {
+    fn new(rect: LayerRect,
+           sub_rect: TexelRect,
+           repeat_horizontal: RepeatMode,
+           repeat_vertical: RepeatMode) -> ImageBorderSegment {
+        let tile_spacing = LayerSize::zero();
+
+        debug_assert!(sub_rect.uv1.x >= sub_rect.uv0.x);
+        debug_assert!(sub_rect.uv1.y >= sub_rect.uv0.y);
+
+        let image_size = LayerSize::new(sub_rect.uv1.x - sub_rect.uv0.x,
+                                        sub_rect.uv1.y - sub_rect.uv0.y);
+
+        let stretch_size_x = match repeat_horizontal {
+            RepeatMode::Stretch => rect.size.width,
+            RepeatMode::Repeat => image_size.width,
+            RepeatMode::Round | RepeatMode::Space => {
+                println!("Round/Space not supported yet!");
+                rect.size.width
+            }
+        };
+
+        let stretch_size_y = match repeat_vertical {
+            RepeatMode::Stretch => rect.size.height,
+            RepeatMode::Repeat => image_size.height,
+            RepeatMode::Round | RepeatMode::Space => {
+                println!("Round/Space not supported yet!");
+                rect.size.height
+            }
+        };
+
+        ImageBorderSegment {
+            geom_rect: rect,
+            sub_rect: sub_rect,
+            stretch_size: LayerSize::new(stretch_size_x, stretch_size_y),
+            tile_spacing: tile_spacing,
+        }
+    }
+}
 
 #[derive(Clone, Copy)]
 pub struct FrameBuilderConfig {
     pub enable_scrollbars: bool,
     pub enable_subpixel_aa: bool,
     pub debug: bool,
 }
 
@@ -57,39 +105,42 @@ pub struct FrameBuilder {
     screen_rect: LayerRect,
     background_color: Option<ColorF>,
     prim_store: PrimitiveStore,
     cmds: Vec<PrimitiveRunCmd>,
     config: FrameBuilderConfig,
 
     stacking_context_store: Vec<StackingContext>,
     scroll_layer_store: Vec<ScrollLayer>,
+    clip_scroll_group_store: Vec<ClipScrollGroup>,
     packed_layers: Vec<PackedLayer>,
 
     scrollbar_prims: Vec<ScrollbarPrimitive>,
 
-    /// A stack of scroll layers used during building to properly parent new scroll layers.
-    scroll_layer_stack: Vec<ScrollLayerIndex>,
+    /// A stack of scroll nodes used during display list processing to properly
+    /// parent new scroll nodes.
+    clip_scroll_node_stack: Vec<ScrollLayerIndex>,
 }
 
 impl FrameBuilder {
     pub fn new(viewport_size: LayerSize,
                background_color: Option<ColorF>,
                config: FrameBuilderConfig) -> FrameBuilder {
         FrameBuilder {
             screen_rect: LayerRect::new(LayerPoint::zero(), viewport_size),
             background_color: background_color,
             stacking_context_store: Vec::new(),
             scroll_layer_store: Vec::new(),
+            clip_scroll_group_store: Vec::new(),
             prim_store: PrimitiveStore::new(),
             cmds: Vec::new(),
             packed_layers: Vec::new(),
             scrollbar_prims: Vec::new(),
             config: config,
-            scroll_layer_stack: Vec::new(),
+            clip_scroll_node_stack: Vec::new(),
         }
     }
 
     fn add_primitive(&mut self,
                      rect: &LayerRect,
                      clip_region: &ClipRegion,
                      container: PrimitiveContainer) -> PrimitiveIndex {
 
@@ -123,88 +174,103 @@ impl FrameBuilder {
             &mut PrimitiveRunCmd::PopScrollLayer => {}
         }
 
         self.cmds.push(PrimitiveRunCmd::PrimitiveRun(prim_index, 1));
 
         prim_index
     }
 
+    pub fn create_clip_scroll_group(&mut self,
+                                    stacking_context_index: StackingContextIndex,
+                                    scroll_layer_id: ScrollLayerId,
+                                    pipeline_id: PipelineId)
+                                    -> ClipScrollGroupIndex {
+        let packed_layer_index = PackedLayerIndex(self.packed_layers.len());
+        self.packed_layers.push(PackedLayer::empty());
+
+        self.clip_scroll_group_store.push(ClipScrollGroup {
+            stacking_context_index: stacking_context_index,
+            scroll_layer_id: scroll_layer_id,
+            packed_layer_index: packed_layer_index,
+            pipeline_id: pipeline_id,
+            xf_rect: None,
+         });
+
+        ClipScrollGroupIndex(self.clip_scroll_group_store.len() - 1)
+    }
+
     pub fn push_stacking_context(&mut self,
                                  rect: LayerRect,
                                  transform: LayerToScrollTransform,
                                  pipeline_id: PipelineId,
                                  scroll_layer_id: ScrollLayerId,
                                  composite_ops: CompositeOps) {
         let stacking_context_index = StackingContextIndex(self.stacking_context_store.len());
-        let packed_layer_index = PackedLayerIndex(self.packed_layers.len());
-
-        self.stacking_context_store.push(StackingContext {
-            local_rect: rect,
-            local_transform: transform,
-            scroll_layer_id: scroll_layer_id,
-            pipeline_id: pipeline_id,
-            xf_rect: None,
-            composite_ops: composite_ops,
-            packed_layer_index: packed_layer_index,
-        });
-        self.packed_layers.push(PackedLayer::empty());
+        let group_index = self.create_clip_scroll_group(stacking_context_index,
+                                                        scroll_layer_id,
+                                                        pipeline_id);
+        self.stacking_context_store.push(StackingContext::new(pipeline_id,
+                                                              transform,
+                                                              rect,
+                                                              composite_ops,
+                                                              group_index));
         self.cmds.push(PrimitiveRunCmd::PushStackingContext(stacking_context_index));
-
     }
 
     pub fn pop_stacking_context(&mut self) {
         self.cmds.push(PrimitiveRunCmd::PopStackingContext);
     }
 
-    pub fn push_scroll_layer(&mut self,
-                             scroll_layer_id: ScrollLayerId,
-                             clip_region: &ClipRegion,
-                             iframe_origin: &LayerPoint,
-                             content_size: &LayerSize) {
+    pub fn push_clip_scroll_node(&mut self,
+                                 scroll_layer_id: ScrollLayerId,
+                                 clip_region: &ClipRegion,
+                                 node_origin: &LayerPoint,
+                                 content_size: &LayerSize) {
         let scroll_layer_index = ScrollLayerIndex(self.scroll_layer_store.len());
+        let parent_index = *self.clip_scroll_node_stack.last().unwrap_or(&scroll_layer_index);
+        self.clip_scroll_node_stack.push(scroll_layer_index);
+
         let packed_layer_index = PackedLayerIndex(self.packed_layers.len());
 
         let clip_source = ClipSource::Region(clip_region.clone());
         let clip_info = MaskCacheInfo::new(&clip_source,
                                            true, // needs an extra clip for the clip rectangle
                                            &mut self.prim_store.gpu_data32);
 
-        let parent_index = *self.scroll_layer_stack.last().unwrap_or(&scroll_layer_index);
         self.scroll_layer_store.push(ScrollLayer {
             scroll_layer_id: scroll_layer_id,
             parent_index: parent_index,
             clip_source: clip_source,
             clip_cache_info: clip_info,
             xf_rect: None,
             packed_layer_index: packed_layer_index,
         });
         self.packed_layers.push(PackedLayer::empty());
         self.cmds.push(PrimitiveRunCmd::PushScrollLayer(scroll_layer_index));
 
 
         // We need to push a fake stacking context here, because primitives that are
         // direct children of this stacking context, need to be adjusted by the scroll
         // offset of this layer. Eventually we should be able to remove this.
         let rect = LayerRect::new(LayerPoint::zero(),
-                                  LayerSize::new(content_size.width + iframe_origin.x,
-                                                 content_size.height + iframe_origin.y));
+                                  LayerSize::new(content_size.width + node_origin.x,
+                                                 content_size.height + node_origin.y));
         self.push_stacking_context(rect,
                                    LayerToScrollTransform::identity(),
                                    scroll_layer_id.pipeline_id,
                                    scroll_layer_id,
                                    CompositeOps::empty());
 
-        self.scroll_layer_stack.push(scroll_layer_index);
     }
 
-    pub fn pop_scroll_layer(&mut self) {
+    pub fn pop_clip_scroll_node(&mut self) {
         self.pop_stacking_context();
         self.cmds.push(PrimitiveRunCmd::PopScrollLayer);
-        self.scroll_layer_stack.pop();
+        self.clip_scroll_node_stack.pop();
     }
 
     pub fn add_solid_rectangle(&mut self,
                                rect: &LayerRect,
                                clip_region: &ClipRegion,
                                color: &ColorF,
                                flags: PrimitiveFlags) {
         if color.a == 0.0 {
@@ -249,128 +315,233 @@ impl FrameBuilder {
                 return false;
             }
         }
     }
 
     pub fn add_border(&mut self,
                       rect: LayerRect,
                       clip_region: &ClipRegion,
-                      border: &BorderDisplayItem) {
-        let radius = &border.radius;
-        let left = &border.left;
-        let right = &border.right;
-        let top = &border.top;
-        let bottom = &border.bottom;
-
-        if !self.supported_style(left) || !self.supported_style(right) ||
-           !self.supported_style(top) || !self.supported_style(bottom) {
-            println!("Unsupported border style, not rendering border");
-            return;
-        }
+                      border_item: &BorderDisplayItem) {
+        match border_item.details {
+            BorderDetails::Image(ref border) => {
+                // Calculate the modified rect as specific by border-image-outset
+                let origin = LayerPoint::new(rect.origin.x - border.outset.left,
+                                             rect.origin.y - border.outset.top);
+                let size = LayerSize::new(rect.size.width + border.outset.left + border.outset.right,
+                                          rect.size.height + border.outset.top + border.outset.bottom);
+                let rect = LayerRect::new(origin, size);
 
-        // These colors are used during inset/outset scaling.
-        let left_color      = left.border_color(1.0, 2.0/3.0, 0.3, 0.7);
-        let top_color       = top.border_color(1.0, 2.0/3.0, 0.3, 0.7);
-        let right_color     = right.border_color(2.0/3.0, 1.0, 0.7, 0.3);
-        let bottom_color    = bottom.border_color(2.0/3.0, 1.0, 0.7, 0.3);
+                // Calculate the local texel coords of the slices.
+                let px0 = 0;
+                let px1 = border.patch.slice.left;
+                let px2 = border.patch.width - border.patch.slice.right;
+                let px3 = border.patch.width;
 
-        let tl_outer = LayerPoint::new(rect.origin.x, rect.origin.y);
-        let tl_inner = tl_outer + LayerPoint::new(radius.top_left.width.max(left.width),
-                                                  radius.top_left.height.max(top.width));
+                let py0 = 0;
+                let py1 = border.patch.slice.top;
+                let py2 = border.patch.height - border.patch.slice.bottom;
+                let py3 = border.patch.height;
 
-        let tr_outer = LayerPoint::new(rect.origin.x + rect.size.width, rect.origin.y);
-        let tr_inner = tr_outer + LayerPoint::new(-radius.top_right.width.max(right.width),
-                                                  radius.top_right.height.max(top.width));
+                let tl_outer = LayerPoint::new(rect.origin.x, rect.origin.y);
+                let tl_inner = tl_outer + LayerPoint::new(border_item.widths.left, border_item.widths.top);
 
-        let bl_outer = LayerPoint::new(rect.origin.x, rect.origin.y + rect.size.height);
-        let bl_inner = bl_outer + LayerPoint::new(radius.bottom_left.width.max(left.width),
-                                                  -radius.bottom_left.height.max(bottom.width));
+                let tr_outer = LayerPoint::new(rect.origin.x + rect.size.width, rect.origin.y);
+                let tr_inner = tr_outer + LayerPoint::new(-border_item.widths.right, border_item.widths.top);
+
+                let bl_outer = LayerPoint::new(rect.origin.x, rect.origin.y + rect.size.height);
+                let bl_inner = bl_outer + LayerPoint::new(border_item.widths.left, -border_item.widths.bottom);
 
-        let br_outer = LayerPoint::new(rect.origin.x + rect.size.width,
-                                       rect.origin.y + rect.size.height);
-        let br_inner = br_outer - LayerPoint::new(radius.bottom_right.width.max(right.width),
-                                                  radius.bottom_right.height.max(bottom.width));
+                let br_outer = LayerPoint::new(rect.origin.x + rect.size.width,
+                                               rect.origin.y + rect.size.height);
+                let br_inner = br_outer - LayerPoint::new(border_item.widths.right, border_item.widths.bottom);
+
+                // Build the list of image segments
+                let mut segments = vec![
+                    // Top left
+                    ImageBorderSegment::new(LayerRect::from_floats(tl_outer.x, tl_outer.y, tl_inner.x, tl_inner.y),
+                                            TexelRect::new(px0, py0, px1, py1),
+                                            RepeatMode::Stretch,
+                                            RepeatMode::Stretch),
 
-        // The border shader is quite expensive. For simple borders, we can just draw
-        // the border with a few rectangles. This generally gives better batching, and
-        // a GPU win in fragment shader time.
-        // More importantly, the software (OSMesa) implementation we run tests on is
-        // particularly slow at running our complex border shader, compared to the
-        // rectangle shader. This has the effect of making some of our tests time
-        // out more often on CI (the actual cause is simply too many Servo processes and
-        // threads being run on CI at once).
-        // TODO(gw): Detect some more simple cases and handle those with simpler shaders too.
-        // TODO(gw): Consider whether it's only worth doing this for large rectangles (since
-        //           it takes a little more CPU time to handle multiple rectangles compared
-        //           to a single border primitive).
-        if left.style == BorderStyle::Solid {
-            let same_color = left_color == top_color &&
-                             left_color == right_color &&
-                             left_color == bottom_color;
-            let same_style = left.style == top.style &&
-                             left.style == right.style &&
-                             left.style == bottom.style;
+                    // Top right
+                    ImageBorderSegment::new(LayerRect::from_floats(tr_inner.x, tr_outer.y, tr_outer.x, tr_inner.y),
+                                            TexelRect::new(px2, py0, px3, py1),
+                                            RepeatMode::Stretch,
+                                            RepeatMode::Stretch),
 
-            if same_color && same_style && radius.is_zero() {
-                let rects = [
-                    LayerRect::new(rect.origin,
-                                   LayerSize::new(rect.size.width, top.width)),
-                    LayerRect::new(LayerPoint::new(tl_outer.x, tl_inner.y),
-                                   LayerSize::new(left.width,
-                                                  rect.size.height - top.width - bottom.width)),
-                    LayerRect::new(tr_inner,
-                                   LayerSize::new(right.width,
-                                                  rect.size.height - top.width - bottom.width)),
-                    LayerRect::new(LayerPoint::new(bl_outer.x, bl_inner.y),
-                                   LayerSize::new(rect.size.width, bottom.width))
+                    // Bottom right
+                    ImageBorderSegment::new(LayerRect::from_floats(br_inner.x, br_inner.y, br_outer.x, br_outer.y),
+                                            TexelRect::new(px2, py2, px3, py3),
+                                            RepeatMode::Stretch,
+                                            RepeatMode::Stretch),
+
+                    // Bottom left
+                    ImageBorderSegment::new(LayerRect::from_floats(bl_outer.x, bl_inner.y, bl_inner.x, bl_outer.y),
+                                            TexelRect::new(px0, py2, px1, py3),
+                                            RepeatMode::Stretch,
+                                            RepeatMode::Stretch),
                 ];
 
-                for rect in &rects {
-                    self.add_solid_rectangle(rect,
-                                             clip_region,
-                                             &top_color,
-                                             PrimitiveFlags::None);
+                // Add edge segments if valid size.
+                if px1 < px2 && py1 < py2 {
+                    segments.extend_from_slice(&[
+                        // Top
+                        ImageBorderSegment::new(LayerRect::from_floats(tl_inner.x, tl_outer.y, tr_inner.x, tl_inner.y),
+                                                TexelRect::new(px1, py0, px2, py1),
+                                                border.repeat_horizontal,
+                                                RepeatMode::Stretch),
+
+                        // Bottom
+                        ImageBorderSegment::new(LayerRect::from_floats(bl_inner.x, bl_inner.y, br_inner.x, bl_outer.y),
+                                                TexelRect::new(px1, py2, px2, py3),
+                                                border.repeat_horizontal,
+                                                RepeatMode::Stretch),
+
+                        // Left
+                        ImageBorderSegment::new(LayerRect::from_floats(tl_outer.x, tl_inner.y, tl_inner.x, bl_inner.y),
+                                                TexelRect::new(px0, py1, px1, py2),
+                                                RepeatMode::Stretch,
+                                                border.repeat_vertical),
+
+                        // Right
+                        ImageBorderSegment::new(LayerRect::from_floats(tr_inner.x, tr_inner.y, br_outer.x, br_inner.y),
+                                                TexelRect::new(px2, py1, px3, py2),
+                                                RepeatMode::Stretch,
+                                                border.repeat_vertical),
+                    ]);
+                }
+
+                for segment in segments {
+                    self.add_image(segment.geom_rect,
+                                   clip_region,
+                                   &segment.stretch_size,
+                                   &segment.tile_spacing,
+                                   Some(segment.sub_rect),
+                                   border.image_key,
+                                   ImageRendering::Auto);
+                }
+            }
+            BorderDetails::Normal(ref border) => {
+                let radius = &border.radius;
+                let left = &border.left;
+                let right = &border.right;
+                let top = &border.top;
+                let bottom = &border.bottom;
+
+                if !self.supported_style(left) || !self.supported_style(right) ||
+                   !self.supported_style(top) || !self.supported_style(bottom) {
+                    println!("Unsupported border style, not rendering border");
+                    return;
                 }
 
-                return;
+                // These colors are used during inset/outset scaling.
+                let left_color      = left.border_color(1.0, 2.0/3.0, 0.3, 0.7);
+                let top_color       = top.border_color(1.0, 2.0/3.0, 0.3, 0.7);
+                let right_color     = right.border_color(2.0/3.0, 1.0, 0.7, 0.3);
+                let bottom_color    = bottom.border_color(2.0/3.0, 1.0, 0.7, 0.3);
+
+                let tl_outer = LayerPoint::new(rect.origin.x, rect.origin.y);
+                let tl_inner = tl_outer + LayerPoint::new(radius.top_left.width.max(border_item.widths.left),
+                                                          radius.top_left.height.max(border_item.widths.top));
+
+                let tr_outer = LayerPoint::new(rect.origin.x + rect.size.width, rect.origin.y);
+                let tr_inner = tr_outer + LayerPoint::new(-radius.top_right.width.max(border_item.widths.right),
+                                                          radius.top_right.height.max(border_item.widths.top));
+
+                let bl_outer = LayerPoint::new(rect.origin.x, rect.origin.y + rect.size.height);
+                let bl_inner = bl_outer + LayerPoint::new(radius.bottom_left.width.max(border_item.widths.left),
+                                                          -radius.bottom_left.height.max(border_item.widths.bottom));
+
+                let br_outer = LayerPoint::new(rect.origin.x + rect.size.width,
+                                               rect.origin.y + rect.size.height);
+                let br_inner = br_outer - LayerPoint::new(radius.bottom_right.width.max(border_item.widths.right),
+                                                          radius.bottom_right.height.max(border_item.widths.bottom));
+
+                // The border shader is quite expensive. For simple borders, we can just draw
+                // the border with a few rectangles. This generally gives better batching, and
+                // a GPU win in fragment shader time.
+                // More importantly, the software (OSMesa) implementation we run tests on is
+                // particularly slow at running our complex border shader, compared to the
+                // rectangle shader. This has the effect of making some of our tests time
+                // out more often on CI (the actual cause is simply too many Servo processes and
+                // threads being run on CI at once).
+                // TODO(gw): Detect some more simple cases and handle those with simpler shaders too.
+                // TODO(gw): Consider whether it's only worth doing this for large rectangles (since
+                //           it takes a little more CPU time to handle multiple rectangles compared
+                //           to a single border primitive).
+                if left.style == BorderStyle::Solid {
+                    let same_color = left_color == top_color &&
+                                     left_color == right_color &&
+                                     left_color == bottom_color;
+                    let same_style = left.style == top.style &&
+                                     left.style == right.style &&
+                                     left.style == bottom.style;
+
+                    if same_color && same_style && radius.is_zero() {
+                        let rects = [
+                            LayerRect::new(rect.origin,
+                                           LayerSize::new(rect.size.width, border_item.widths.top)),
+                            LayerRect::new(LayerPoint::new(tl_outer.x, tl_inner.y),
+                                           LayerSize::new(border_item.widths.left,
+                                                          rect.size.height - border_item.widths.top - border_item.widths.bottom)),
+                            LayerRect::new(tr_inner,
+                                           LayerSize::new(border_item.widths.right,
+                                                          rect.size.height - border_item.widths.top - border_item.widths.bottom)),
+                            LayerRect::new(LayerPoint::new(bl_outer.x, bl_inner.y),
+                                           LayerSize::new(rect.size.width, border_item.widths.bottom))
+                        ];
+
+                        for rect in &rects {
+                            self.add_solid_rectangle(rect,
+                                                     clip_region,
+                                                     &top_color,
+                                                     PrimitiveFlags::None);
+                        }
+
+                        return;
+                    }
+                }
+
+                //Note: while similar to `ComplexClipRegion::get_inner_rect()` in spirit,
+                // this code is a bit more complex and can not there for be merged.
+                let inner_rect = rect_from_points_f(tl_inner.x.max(bl_inner.x),
+                                                    tl_inner.y.max(tr_inner.y),
+                                                    tr_inner.x.min(br_inner.x),
+                                                    bl_inner.y.min(br_inner.y));
+
+                let prim_cpu = BorderPrimitiveCpu {
+                    inner_rect: LayerRect::from_untyped(&inner_rect),
+                };
+
+                let prim_gpu = BorderPrimitiveGpu {
+                    colors: [ left_color, top_color, right_color, bottom_color ],
+                    widths: [ border_item.widths.left,
+                              border_item.widths.top,
+                              border_item.widths.right,
+                              border_item.widths.bottom ],
+                    style: [
+                        pack_as_float(left.style as u32),
+                        pack_as_float(top.style as u32),
+                        pack_as_float(right.style as u32),
+                        pack_as_float(bottom.style as u32),
+                    ],
+                    radii: [
+                        radius.top_left,
+                        radius.top_right,
+                        radius.bottom_right,
+                        radius.bottom_left,
+                    ],
+                };
+
+                self.add_primitive(&rect,
+                                   clip_region,
+                                   PrimitiveContainer::Border(prim_cpu, prim_gpu));
             }
         }
-
-        //Note: while similar to `ComplexClipRegion::get_inner_rect()` in spirit,
-        // this code is a bit more complex and can not there for be merged.
-        let inner_rect = rect_from_points_f(tl_inner.x.max(bl_inner.x),
-                                            tl_inner.y.max(tr_inner.y),
-                                            tr_inner.x.min(br_inner.x),
-                                            bl_inner.y.min(br_inner.y));
-
-        let prim_cpu = BorderPrimitiveCpu {
-            inner_rect: LayerRect::from_untyped(&inner_rect),
-        };
-
-        let prim_gpu = BorderPrimitiveGpu {
-            colors: [ left_color, top_color, right_color, bottom_color ],
-            widths: [ left.width, top.width, right.width, bottom.width ],
-            style: [
-                pack_as_float(left.style as u32),
-                pack_as_float(top.style as u32),
-                pack_as_float(right.style as u32),
-                pack_as_float(bottom.style as u32),
-            ],
-            radii: [
-                radius.top_left,
-                radius.top_right,
-                radius.bottom_right,
-                radius.bottom_left,
-            ],
-        };
-
-        self.add_primitive(&rect,
-                           clip_region,
-                           PrimitiveContainer::Border(prim_cpu, prim_gpu));
     }
 
     pub fn add_gradient(&mut self,
                         rect: LayerRect,
                         clip_region: &ClipRegion,
                         start_point: LayerPoint,
                         end_point: LayerPoint,
                         stops: ItemRange,
@@ -536,67 +707,118 @@ impl FrameBuilder {
         if blur_radius == 0.0 && spread_radius == 0.0 && clip_mode == BoxShadowClipMode::None {
             self.add_solid_rectangle(&box_bounds,
                                      clip_region,
                                      color,
                                      PrimitiveFlags::None);
             return;
         }
 
+        // The local space box shadow rect. It is the element rect
+        // translated by the box shadow offset and inflated by the
+        // box shadow spread.
         let bs_rect = box_bounds.translate(box_offset)
                                 .inflate(spread_radius, spread_radius);
 
+        // Get the outer rectangle, based on the blur radius.
         let outside_edge_size = 2.0 * blur_radius;
         let inside_edge_size = outside_edge_size.max(border_radius);
         let edge_size = outside_edge_size + inside_edge_size;
         let outer_rect = bs_rect.inflate(outside_edge_size, outside_edge_size);
-        let mut instance_rects = Vec::new();
-        let (prim_rect, inverted) = match clip_mode {
+
+        // Box shadows are often used for things like text underline and other
+        // simple primitives, so we want to draw these simple cases with the
+        // solid rectangle shader wherever possible, to avoid invoking the
+        // expensive box-shadow shader.
+        enum BoxShadowKind {
+            Simple(Vec<LayerRect>),     // Can be drawn via simple rectangles only
+            Shadow(Vec<LayerRect>),     // Requires the full box-shadow code path
+        }
+
+        let shadow_kind = match clip_mode {
             BoxShadowClipMode::Outset | BoxShadowClipMode::None => {
-                subtract_rect(&outer_rect, box_bounds, &mut instance_rects);
-                (outer_rect, 0.0)
+                // For outset shadows, subtracting the element rectangle
+                // from the outer rectangle gives the rectangles we need
+                // to draw. In the simple case (no blur radius), we can
+                // just draw these as solid colors.
+                let mut rects = Vec::new();
+                subtract_rect(&outer_rect, box_bounds, &mut rects);
+                if edge_size == 0.0 {
+                    BoxShadowKind::Simple(rects)
+                } else {
+                    BoxShadowKind::Shadow(rects)
+                }
             }
             BoxShadowClipMode::Inset => {
-                subtract_rect(box_bounds, &bs_rect, &mut instance_rects);
-                (*box_bounds, 1.0)
+                // For inset shadows, in the simple case (no blur) we
+                // can draw the shadow area by subtracting the box
+                // shadow rect from the element rect (since inset box
+                // shadows never extend past the element rect). However,
+                // in the case of an inset box shadow with blur, we
+                // currently just draw the box shadow over the entire
+                // rect. The opaque parts of the shadow (past the outside
+                // edge of the box-shadow) are handled by the shadow
+                // shader.
+                // TODO(gw): We should be able to optimize the complex
+                //           inset shadow case to touch fewer pixels. We
+                //           can probably calculate the inner rect that
+                //           can't be affected, and subtract that from
+                //           the element rect?
+                let mut rects = Vec::new();
+                if edge_size == 0.0 {
+                    subtract_rect(box_bounds, &bs_rect, &mut rects);
+                    BoxShadowKind::Simple(rects)
+                } else {
+                    rects.push(*box_bounds);
+                    BoxShadowKind::Shadow(rects)
+                }
             }
         };
 
-        if edge_size == 0.0 {
-            for rect in &instance_rects {
-                self.add_solid_rectangle(rect,
-                                         clip_region,
-                                         color,
-                                         PrimitiveFlags::None)
+        match shadow_kind {
+            BoxShadowKind::Simple(rects) => {
+                for rect in &rects {
+                    self.add_solid_rectangle(rect,
+                                             clip_region,
+                                             color,
+                                             PrimitiveFlags::None)
+                }
             }
-        } else {
-            let prim_gpu = BoxShadowPrimitiveGpu {
-                src_rect: *box_bounds,
-                bs_rect: bs_rect,
-                color: *color,
-                blur_radius: blur_radius,
-                border_radius: border_radius,
-                edge_size: edge_size,
-                inverted: inverted,
-            };
+            BoxShadowKind::Shadow(rects) => {
+                let inverted = match clip_mode {
+                    BoxShadowClipMode::Outset | BoxShadowClipMode::None => 0.0,
+                    BoxShadowClipMode::Inset => 1.0,
+                };
 
-            self.add_primitive(&prim_rect,
-                               clip_region,
-                               PrimitiveContainer::BoxShadow(prim_gpu, instance_rects));
+                let prim_gpu = BoxShadowPrimitiveGpu {
+                    src_rect: *box_bounds,
+                    bs_rect: bs_rect,
+                    color: *color,
+                    blur_radius: blur_radius,
+                    border_radius: border_radius,
+                    edge_size: edge_size,
+                    inverted: inverted,
+                };
+
+                self.add_primitive(&outer_rect,
+                                   clip_region,
+                                   PrimitiveContainer::BoxShadow(prim_gpu, rects));
+            }
         }
     }
 
     pub fn add_webgl_rectangle(&mut self,
                                rect: LayerRect,
                                clip_region: &ClipRegion,
                                context_id: WebGLContextId) {
         let prim_cpu = ImagePrimitiveCpu {
             kind: ImagePrimitiveKind::WebGL(context_id),
             color_texture_id: SourceTexture::Invalid,
             resource_address: GpuStoreAddress(0),
+            sub_rect: None,
         };
 
         let prim_gpu = ImagePrimitiveGpu {
             stretch_size: rect.size,
             tile_spacing: LayerSize::zero(),
         };
 
         self.add_primitive(&rect,
@@ -604,24 +826,26 @@ impl FrameBuilder {
                            PrimitiveContainer::Image(prim_cpu, prim_gpu));
     }
 
     pub fn add_image(&mut self,
                      rect: LayerRect,
                      clip_region: &ClipRegion,
                      stretch_size: &LayerSize,
                      tile_spacing: &LayerSize,
+                     sub_rect: Option<TexelRect>,
                      image_key: ImageKey,
                      image_rendering: ImageRendering) {
         let prim_cpu = ImagePrimitiveCpu {
             kind: ImagePrimitiveKind::Image(image_key,
                                             image_rendering,
                                             *tile_spacing),
             color_texture_id: SourceTexture::Invalid,
             resource_address: GpuStoreAddress(0),
+            sub_rect: sub_rect,
         };
 
         let prim_gpu = ImagePrimitiveGpu {
             stretch_size: *stretch_size,
             tile_spacing: *tile_spacing,
         };
 
         self.add_primitive(&rect,
@@ -652,60 +876,60 @@ impl FrameBuilder {
                            clip_region,
                            PrimitiveContainer::YuvImage(prim_cpu, prim_gpu));
     }
 
     /// Compute the contribution (bounding rectangles, and resources) of layers and their
     /// primitives in screen space.
     fn build_layer_screen_rects_and_cull_layers(&mut self,
                                                 screen_rect: &DeviceIntRect,
-                                                scroll_tree: &ScrollTree,
+                                                clip_scroll_tree: &ClipScrollTree,
                                                 auxiliary_lists_map: &AuxiliaryListsMap,
                                                 resource_cache: &mut ResourceCache,
                                                 profile_counters: &mut FrameProfileCounters,
                                                 device_pixel_ratio: f32) {
         profile_scope!("cull");
         LayerRectCalculationAndCullingPass::create_and_run(self,
                                                            screen_rect,
-                                                           scroll_tree,
+                                                           clip_scroll_tree,
                                                            auxiliary_lists_map,
                                                            resource_cache,
                                                            profile_counters,
                                                            device_pixel_ratio);
     }
 
-    fn update_scroll_bars(&mut self, scroll_tree: &ScrollTree) {
+    fn update_scroll_bars(&mut self, clip_scroll_tree: &ClipScrollTree) {
         let distance_from_edge = 8.0;
 
         for scrollbar_prim in &self.scrollbar_prims {
             let mut geom = (*self.prim_store.gpu_geometry.get(GpuStoreAddress(scrollbar_prim.prim_index.0 as i32))).clone();
-            let scroll_layer = &scroll_tree.layers[&scrollbar_prim.scroll_layer_id];
+            let clip_scroll_node = &clip_scroll_tree.nodes[&scrollbar_prim.scroll_layer_id];
 
-            let scrollable_distance = scroll_layer.scrollable_height();
+            let scrollable_distance = clip_scroll_node.scrollable_height();
 
             if scrollable_distance <= 0.0 {
                 geom.local_clip_rect.size = LayerSize::zero();
                 *self.prim_store.gpu_geometry.get_mut(GpuStoreAddress(scrollbar_prim.prim_index.0 as i32)) = geom;
                 continue;
             }
 
-            let f = -scroll_layer.scrolling.offset.y / scrollable_distance;
+            let f = -clip_scroll_node.scrolling.offset.y / scrollable_distance;
 
-            let min_y = scroll_layer.local_viewport_rect.origin.y -
-                        scroll_layer.scrolling.offset.y +
+            let min_y = clip_scroll_node.local_viewport_rect.origin.y -
+                        clip_scroll_node.scrolling.offset.y +
                         distance_from_edge;
 
-            let max_y = scroll_layer.local_viewport_rect.origin.y +
-                        scroll_layer.local_viewport_rect.size.height -
-                        scroll_layer.scrolling.offset.y -
+            let max_y = clip_scroll_node.local_viewport_rect.origin.y +
+                        clip_scroll_node.local_viewport_rect.size.height -
+                        clip_scroll_node.scrolling.offset.y -
                         geom.local_rect.size.height -
                         distance_from_edge;
 
-            geom.local_rect.origin.x = scroll_layer.local_viewport_rect.origin.x +
-                                       scroll_layer.local_viewport_rect.size.width -
+            geom.local_rect.origin.x = clip_scroll_node.local_viewport_rect.origin.x +
+                                       clip_scroll_node.local_viewport_rect.size.width -
                                        geom.local_rect.size.width -
                                        distance_from_edge;
 
             geom.local_rect.origin.y = util::lerp(min_y, max_y, f);
             geom.local_clip_rect = geom.local_rect;
 
             let clip_source = if scrollbar_prim.border_radius == 0.0 {
                 ClipSource::NoClip
@@ -731,38 +955,37 @@ impl FrameBuilder {
         let mut alpha_task_stack = Vec::new();
 
         for cmd in &self.cmds {
             match *cmd {
                 PrimitiveRunCmd::PushStackingContext(stacking_context_index) => {
                     let stacking_context = &self.stacking_context_store[stacking_context_index.0];
                     sc_stack.push(stacking_context_index);
 
-                    if !stacking_context.is_visible() {
+                    if !stacking_context.is_visible {
                         continue;
                     }
 
+                    let stacking_context_rect = &stacking_context.bounding_rect;
                     let composite_count = stacking_context.composite_ops.count();
                     for _ in 0..composite_count {
-                        let stacking_context_rect =
-                            stacking_context.xf_rect.as_ref().unwrap().bounding_rect;
                         let location = RenderTaskLocation::Dynamic(None, stacking_context_rect.size);
                         let new_task = RenderTask::new_alpha_batch(next_task_index,
                                                                    stacking_context_rect.origin,
                                                                    location);
                         next_task_index.0 += 1;
                         let prev_task = mem::replace(&mut current_task, new_task);
                         alpha_task_stack.push(prev_task);
                     }
                 }
                 PrimitiveRunCmd::PopStackingContext => {
                     let stacking_context_index = sc_stack.pop().unwrap();
                     let stacking_context = &self.stacking_context_store[stacking_context_index.0];
 
-                    if !stacking_context.is_visible() {
+                    if !stacking_context.is_visible {
                         continue;
                     }
 
                     for filter in &stacking_context.composite_ops.filters {
                         let mut prev_task = alpha_task_stack.pop().unwrap();
                         let item = AlphaRenderItem::Blend(stacking_context_index,
                                                           current_task.id,
                                                           *filter,
@@ -781,20 +1004,19 @@ impl FrameBuilder {
                                                                               op,
                                                                               next_z);
                                 next_z += 1;
                                 prev_task.as_alpha_batch().alpha_items.push(item);
                                 prev_task.children.push(current_task);
                                 current_task = prev_task;
                             }
                             None => {
-                                let stacking_context_rect =
-                                    stacking_context.xf_rect.as_ref().unwrap().bounding_rect;
                                 let readback_task =
-                                    RenderTask::new_readback(stacking_context_index, stacking_context_rect);
+                                    RenderTask::new_readback(stacking_context_index,
+                                                             stacking_context.bounding_rect);
 
                                 let mut prev_task = alpha_task_stack.pop().unwrap();
                                 let item = AlphaRenderItem::Composite(stacking_context_index,
                                                                       readback_task.id,
                                                                       current_task.id,
                                                                       mix_blend_mode,
                                                                       next_z);
                                 next_z += 1;
@@ -805,64 +1027,67 @@ impl FrameBuilder {
                             }
                         }
                     }
                 }
                 PrimitiveRunCmd::PrimitiveRun(first_prim_index, prim_count) => {
                     let stacking_context_index = *sc_stack.last().unwrap();
                     let stacking_context = &self.stacking_context_store[stacking_context_index.0];
 
-                    if !stacking_context.is_visible() {
+                    if !stacking_context.is_visible {
                         continue;
                     }
 
+                    let stacking_context_index = *sc_stack.last().unwrap();
+                    let group_index =
+                        self.stacking_context_store[stacking_context_index.0].clip_scroll_group();
+                    let clip_scroll_group = &self.clip_scroll_group_store[group_index.0];
+
                     for i in 0..prim_count {
                         let prim_index = PrimitiveIndex(first_prim_index.0 + i);
 
                         if self.prim_store.cpu_bounding_rects[prim_index.0].is_some() {
                             let prim_metadata = self.prim_store.get_metadata(prim_index);
 
                             // Add any dynamic render tasks needed to render this primitive
                             if let Some(ref render_task) = prim_metadata.render_task {
                                 current_task.children.push(render_task.clone());
                             }
                             if let Some(ref clip_task) = prim_metadata.clip_task {
                                 current_task.children.push(clip_task.clone());
                             }
 
-                            let transform_kind = stacking_context.xf_rect.as_ref().unwrap().kind;
+                            let transform_kind = clip_scroll_group.xf_rect.as_ref().unwrap().kind;
                             let needs_clipping = prim_metadata.clip_task.is_some();
                             let needs_blending = transform_kind == TransformedRectKind::Complex ||
                                                  !prim_metadata.is_opaque ||
                                                  needs_clipping;
 
                             let items = if needs_blending {
                                 &mut current_task.as_alpha_batch().alpha_items
                             } else {
                                 &mut current_task.as_alpha_batch().opaque_items
                             };
-                            items.push(AlphaRenderItem::Primitive(stacking_context_index,
-                                                                  prim_index,
-                                                                  next_z));
+                            items.push(AlphaRenderItem::Primitive(group_index, prim_index, next_z));
                             next_z += 1;
                         }
                     }
                 }
                 PrimitiveRunCmd::PushScrollLayer(_) | PrimitiveRunCmd::PopScrollLayer => { }
             }
         }
 
         debug_assert!(alpha_task_stack.is_empty());
         (current_task, next_task_index.0)
     }
 
     pub fn build(&mut self,
                  resource_cache: &mut ResourceCache,
                  frame_id: FrameId,
-                 scroll_tree: &ScrollTree,
+                 clip_scroll_tree: &ClipScrollTree,
                  auxiliary_lists_map: &AuxiliaryListsMap,
                  device_pixel_ratio: f32) -> Frame {
         profile_scope!("build");
 
         let mut profile_counters = FrameProfileCounters::new();
         profile_counters.total_primitives.set(self.prim_store.prim_count());
 
         resource_cache.begin_frame(frame_id);
@@ -876,20 +1101,20 @@ impl FrameBuilder {
 
         // Pick a size for the cache render targets to be. The main requirement is that it
         // has to be at least as large as the framebuffer size. This ensures that it will
         // always be able to allocate the worst case render task (such as a clip mask that
         // covers the entire screen).
         let cache_size = DeviceUintSize::new(cmp::max(1024, screen_rect.size.width as u32),
                                              cmp::max(1024, screen_rect.size.height as u32));
 
-        self.update_scroll_bars(scroll_tree);
+        self.update_scroll_bars(clip_scroll_tree);
 
         self.build_layer_screen_rects_and_cull_layers(&screen_rect,
-                                                      scroll_tree,
+                                                      clip_scroll_tree,
                                                       auxiliary_lists_map,
                                                       resource_cache,
                                                       &mut profile_counters,
                                                       device_pixel_ratio);
 
         let (main_render_task, static_render_task_count) = self.build_render_task();
         let mut render_tasks = RenderTaskCollection::new(static_render_task_count);
 
@@ -917,16 +1142,17 @@ impl FrameBuilder {
                                         cache_size));
         }
 
         main_render_task.assign_to_passes(passes.len() - 1, &mut passes);
 
         for pass in &mut passes {
             let ctx = RenderTargetContext {
                 stacking_context_store: &self.stacking_context_store,
+                clip_scroll_group_store: &self.clip_scroll_group_store,
                 prim_store: &self.prim_store,
                 resource_cache: resource_cache,
             };
 
             pass.build(&ctx, &mut render_tasks);
 
             profile_counters.passes.inc();
             profile_counters.targets.add(pass.targets.len());
@@ -948,22 +1174,23 @@ impl FrameBuilder {
             gpu_data64: self.prim_store.gpu_data64.build(),
             gpu_data128: self.prim_store.gpu_data128.build(),
             gpu_geometry: self.prim_store.gpu_geometry.build(),
             gpu_gradient_data: self.prim_store.gpu_gradient_data.build(),
             gpu_resource_rects: self.prim_store.gpu_resource_rects.build(),
             deferred_resolves: deferred_resolves,
         }
     }
+
 }
 
 struct LayerRectCalculationAndCullingPass<'a> {
     frame_builder: &'a mut FrameBuilder,
     screen_rect: &'a DeviceIntRect,
-    scroll_tree: &'a ScrollTree,
+    clip_scroll_tree: &'a ClipScrollTree,
     auxiliary_lists_map: &'a AuxiliaryListsMap,
     resource_cache: &'a mut ResourceCache,
     profile_counters: &'a mut FrameProfileCounters,
     device_pixel_ratio: f32,
     stacking_context_stack: Vec<StackingContextIndex>,
     scroll_layer_stack: Vec<ScrollLayerIndex>,
 
     /// A cached clip info stack, which should handle the most common situation,
@@ -973,64 +1200,137 @@ struct LayerRectCalculationAndCullingPas
 
     /// The scroll layer that defines the previous scroll layer info stack.
     current_clip_stack_scroll_layer: Option<ScrollLayerIndex>
 }
 
 impl<'a> LayerRectCalculationAndCullingPass<'a> {
     fn create_and_run(frame_builder: &'a mut FrameBuilder,
                       screen_rect: &'a DeviceIntRect,
-                      scroll_tree: &'a ScrollTree,
+                      clip_scroll_tree: &'a ClipScrollTree,
                       auxiliary_lists_map: &'a AuxiliaryListsMap,
                       resource_cache: &'a mut ResourceCache,
                       profile_counters: &'a mut FrameProfileCounters,
                       device_pixel_ratio: f32) {
 
         let mut pass = LayerRectCalculationAndCullingPass {
             frame_builder: frame_builder,
             screen_rect: screen_rect,
-            scroll_tree: scroll_tree,
+            clip_scroll_tree: clip_scroll_tree,
             auxiliary_lists_map: auxiliary_lists_map,
             resource_cache: resource_cache,
             profile_counters: profile_counters,
             device_pixel_ratio: device_pixel_ratio,
             stacking_context_stack: Vec::new(),
             scroll_layer_stack: Vec::new(),
             current_clip_stack: Vec::new(),
             current_clip_stack_scroll_layer: None,
         };
         pass.run();
     }
 
     fn run(&mut self) {
+        self.recalculate_clip_scroll_groups();
+        self.compute_stacking_context_visibility();
+
         let commands = mem::replace(&mut self.frame_builder.cmds, Vec::new());
         for cmd in &commands {
             match cmd {
                 &PrimitiveRunCmd::PushStackingContext(stacking_context_index) =>
                     self.handle_push_stacking_context(stacking_context_index),
                 &PrimitiveRunCmd::PushScrollLayer(scroll_layer_index) =>
                     self.handle_push_scroll_layer(scroll_layer_index),
                 &PrimitiveRunCmd::PrimitiveRun(prim_index, prim_count) =>
                     self.handle_primitive_run(prim_index, prim_count),
-                &PrimitiveRunCmd::PopStackingContext => {
-                    self.stacking_context_stack.pop();
-                }
+                &PrimitiveRunCmd::PopStackingContext => self.handle_pop_stacking_context(),
                 &PrimitiveRunCmd::PopScrollLayer => self.handle_pop_scroll_layer(),
             }
         }
 
         mem::replace(&mut self.frame_builder.cmds, commands);
     }
 
+    fn recalculate_clip_scroll_groups(&mut self) {
+        for ref mut group in &mut self.frame_builder.clip_scroll_group_store {
+            let stacking_context_index = group.stacking_context_index;
+            let stacking_context = &mut self.frame_builder
+                                            .stacking_context_store[stacking_context_index.0];
+
+            let scroll_tree_layer = &self.clip_scroll_tree.nodes[&group.scroll_layer_id];
+            let packed_layer = &mut self.frame_builder.packed_layers[group.packed_layer_index.0];
+            packed_layer.transform = scroll_tree_layer.world_content_transform
+                                                      .with_source::<ScrollLayerPixel>()
+                                                      .pre_mul(&stacking_context.local_transform);
+            packed_layer.inv_transform = packed_layer.transform.inverse().unwrap();
+
+            if !stacking_context.can_contribute_to_scene() {
+                return;
+            }
+
+            let inv_layer_transform = stacking_context.local_transform.inverse().unwrap();
+            let local_viewport_rect =
+                as_scroll_parent_rect(&scroll_tree_layer.combined_local_viewport_rect);
+            let viewport_rect = inv_layer_transform.transform_rect(&local_viewport_rect);
+            let layer_local_rect = stacking_context.local_rect.intersection(&viewport_rect);
+
+            group.xf_rect = None;
+
+            let layer_local_rect = match layer_local_rect {
+                Some(layer_local_rect) if !layer_local_rect.is_empty() => layer_local_rect,
+                _ => continue,
+            };
+
+            let layer_xf_rect = TransformedRect::new(&layer_local_rect,
+                                                     &packed_layer.transform,
+                                                     self.device_pixel_ratio);
+
+            if layer_xf_rect.bounding_rect.intersects(&self.screen_rect) {
+                packed_layer.screen_vertices = layer_xf_rect.vertices.clone();
+                packed_layer.local_clip_rect = layer_local_rect;
+                group.xf_rect = Some(layer_xf_rect);
+            }
+        }
+    }
+
+    fn compute_stacking_context_visibility(&mut self) {
+        for context_index in 0..self.frame_builder.stacking_context_store.len() {
+            let is_visible = {
+                let stacking_context = &self.frame_builder.stacking_context_store[context_index];
+                stacking_context.clip_scroll_groups.iter().any(|group_index| {
+                    self.frame_builder.clip_scroll_group_store[group_index.0].is_visible()
+                })
+            };
+            self.frame_builder.stacking_context_store[context_index].is_visible = is_visible;
+        }
+    }
+
+    fn handle_pop_stacking_context(&mut self) {
+        let stacking_context_index = self.stacking_context_stack.pop().unwrap();
+
+        let bounding_rect = {
+            let stacking_context =
+                &mut self.frame_builder.stacking_context_store[stacking_context_index.0];
+            stacking_context.bounding_rect = stacking_context.bounding_rect
+                                                             .intersection(self.screen_rect)
+                                                             .unwrap_or(DeviceIntRect::zero());
+            stacking_context.bounding_rect.clone()
+        };
+
+        if let Some(ref mut parent_index) = self.stacking_context_stack.last_mut() {
+            let parent = &mut self.frame_builder.stacking_context_store[parent_index.0];
+            parent.bounding_rect = parent.bounding_rect.union(&bounding_rect);
+        }
+    }
+
     fn handle_push_scroll_layer(&mut self, scroll_layer_index: ScrollLayerIndex) {
         self.scroll_layer_stack.push(scroll_layer_index);
 
         let scroll_layer = &mut self.frame_builder.scroll_layer_store[scroll_layer_index.0];
         let packed_layer_index = scroll_layer.packed_layer_index;
-        let scroll_tree_layer = &self.scroll_tree.layers[&scroll_layer.scroll_layer_id];
+        let scroll_tree_layer = &self.clip_scroll_tree.nodes[&scroll_layer.scroll_layer_id];
         let packed_layer = &mut self.frame_builder.packed_layers[packed_layer_index.0];
 
         packed_layer.transform = scroll_tree_layer.world_viewport_transform;
         packed_layer.inv_transform = packed_layer.transform.inverse().unwrap();
 
         let local_rect = &scroll_tree_layer.combined_local_viewport_rect
                                            .translate(&scroll_tree_layer.scrolling.offset);
         if !local_rect.is_empty() {
@@ -1063,46 +1363,24 @@ impl<'a> LayerRectCalculationAndCullingP
             // We don't add the image mask for resolution, because layer masks are resolved later.
             self.resource_cache.request_image(mask.image, ImageRendering::Auto);
         }
     }
 
     fn handle_push_stacking_context(&mut self, stacking_context_index: StackingContextIndex) {
         self.stacking_context_stack.push(stacking_context_index);
 
+        // Reset bounding rect to zero. We will calculate it as we collect primitives
+        // from various scroll layers. In handle_pop_stacking_context , we use this to
+        // calculate the device bounding rect. In the future, we could cache this during
+        // the initial adding of items for the common case (where there is only a single
+        // scroll layer for items in a stacking context).
         let stacking_context = &mut self.frame_builder
                                         .stacking_context_store[stacking_context_index.0];
-        let packed_layer = &mut self.frame_builder
-                                    .packed_layers[stacking_context.packed_layer_index.0];
-        let scroll_layer = &self.scroll_tree.layers[&stacking_context.scroll_layer_id];
-        packed_layer.transform = scroll_layer.world_content_transform
-                                             .with_source::<ScrollLayerPixel>()
-                                             .pre_mul(&stacking_context.local_transform);
-        packed_layer.inv_transform = packed_layer.transform.inverse().unwrap();
-
-        if !stacking_context.can_contribute_to_scene() {
-            return;
-        }
-
-        let inv_layer_transform = stacking_context.local_transform.inverse().unwrap();
-        let local_viewport_rect = as_scroll_parent_rect(&scroll_layer.combined_local_viewport_rect);
-        let viewport_rect = inv_layer_transform.transform_rect(&local_viewport_rect);
-        let layer_local_rect = stacking_context.local_rect.intersection(&viewport_rect);
-
-        if let Some(layer_local_rect) = layer_local_rect {
-            let layer_xf_rect = TransformedRect::new(&layer_local_rect,
-                                                     &packed_layer.transform,
-                                                     self.device_pixel_ratio);
-
-            if layer_xf_rect.bounding_rect.intersects(&self.screen_rect) {
-                packed_layer.screen_vertices = layer_xf_rect.vertices.clone();
-                packed_layer.local_clip_rect = layer_local_rect;
-                stacking_context.xf_rect = Some(layer_xf_rect);
-            }
-        }
+        stacking_context.bounding_rect = DeviceIntRect::zero();
     }
 
     fn rebuild_clip_info_stack_if_necessary(&mut self, mut scroll_layer_index: ScrollLayerIndex) {
         if let Some(previous_scroll_layer) = self.current_clip_stack_scroll_layer {
             if previous_scroll_layer == scroll_layer_index {
                 return;
             }
         }
@@ -1125,28 +1403,38 @@ impl<'a> LayerRectCalculationAndCullingP
             }
             scroll_layer_index = scroll_layer.parent_index;
         }
 
         self.current_clip_stack.reverse();
     }
 
     fn handle_primitive_run(&mut self, prim_index: PrimitiveIndex, prim_count: usize) {
+        let stacking_context_index = *self.stacking_context_stack.last().unwrap();
+        let (packed_layer_index, pipeline_id) = {
+            let stacking_context =
+                &self.frame_builder.stacking_context_store[stacking_context_index.0];
+
+            if !stacking_context.is_visible {
+                return;
+            }
+
+            let group_index = stacking_context.clip_scroll_group();
+            let clip_scroll_group = &self.frame_builder.clip_scroll_group_store[group_index.0];
+            (clip_scroll_group.packed_layer_index, stacking_context.pipeline_id)
+        };
+
         let scroll_layer_index = *self.scroll_layer_stack.last().unwrap();
         self.rebuild_clip_info_stack_if_necessary(scroll_layer_index);
 
-        let stacking_context_index = self.stacking_context_stack.last().unwrap();
-        let stacking_context = &self.frame_builder.stacking_context_store[stacking_context_index.0];
-        if !stacking_context.is_visible() {
-            return;
-        }
+        let stacking_context =
+            &mut self.frame_builder.stacking_context_store[stacking_context_index.0];
 
-        let packed_layer_index = stacking_context.packed_layer_index;
         let packed_layer = &self.frame_builder.packed_layers[packed_layer_index.0];
-        let auxiliary_lists = self.auxiliary_lists_map.get(&stacking_context.pipeline_id)
+        let auxiliary_lists = self.auxiliary_lists_map.get(&pipeline_id)
                                                       .expect("No auxiliary lists?");
 
         for i in 0..prim_count {
             let prim_index = PrimitiveIndex(prim_index.0 + i);
             if self.frame_builder.prim_store.build_bounding_rect(prim_index,
                                                                  self.screen_rect,
                                                                  &packed_layer.transform,
                                                                  &packed_layer.local_clip_rect,
@@ -1170,16 +1458,19 @@ impl<'a> LayerRectCalculationAndCullingP
                     Some(rect) => rect,
                     _ => continue,
                 };
 
                 let prim_metadata = &mut self.frame_builder.prim_store.cpu_metadata[prim_index.0];
                 let prim_clip_info = prim_metadata.clip_cache_info.as_ref();
                 let mut visible = true;
 
+                stacking_context.bounding_rect =
+                    stacking_context.bounding_rect.union(&prim_bounding_rect);
+
                 if let Some(info) = prim_clip_info {
                     self.current_clip_stack.push((packed_layer_index, info.clone()));
                 }
 
                 // Try to create a mask if we may need to.
                 if !self.current_clip_stack.is_empty() {
                     // If the primitive doesn't have a specific clip, key the task ID off the
                     // stacking context. This means that two primitives which are only clipped
deleted file mode 100644
--- a/gfx/webrender/src/layer.rs
+++ /dev/null
@@ -1,288 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-use euclid::Point3D;
-use geometry::ray_intersects_rect;
-use spring::{DAMPING, STIFFNESS, Spring};
-use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform};
-use webrender_traits::{LayerToWorldTransform, PipelineId, ScrollEventPhase, ScrollLayerId};
-use webrender_traits::{ScrollLayerRect, ScrollLocation, ScrollToWorldTransform, WorldPoint};
-use webrender_traits::{WorldPoint4D};
-
-#[cfg(target_os = "macos")]
-const CAN_OVERSCROLL: bool = true;
-
-#[cfg(not(target_os = "macos"))]
-const CAN_OVERSCROLL: bool = false;
-
-
-/// Contains scrolling and transform information stacking contexts.
-#[derive(Clone)]
-pub struct Layer {
-    /// Manages scrolling offset, overscroll state etc.
-    pub scrolling: ScrollingState,
-
-    /// Size of the content inside the scroll region (in logical pixels)
-    pub content_size: LayerSize,
-
-    /// Viewing rectangle
-    pub local_viewport_rect: LayerRect,
-
-    /// Viewing rectangle clipped against parent layer(s)
-    pub combined_local_viewport_rect: LayerRect,
-
-    /// World transform for the viewport rect itself.
-    pub world_viewport_transform: LayerToWorldTransform,
-
-    /// World transform for content within this layer
-    pub world_content_transform: LayerToWorldTransform,
-
-    /// Transform for this layer, relative to parent scrollable layer.
-    pub local_transform: LayerToScrollTransform,
-
-    /// Pipeline that this layer belongs to
-    pub pipeline_id: PipelineId,
-
-    /// Child layers
-    pub children: Vec<ScrollLayerId>,
-}
-
-impl Layer {
-    pub fn new(local_viewport_rect: &LayerRect,
-               content_size: LayerSize,
-               local_transform: &LayerToScrollTransform,
-               pipeline_id: PipelineId)
-               -> Layer {
-        Layer {
-            scrolling: ScrollingState::new(),
-            content_size: content_size,
-            local_viewport_rect: *local_viewport_rect,
-            combined_local_viewport_rect: *local_viewport_rect,
-            world_viewport_transform: LayerToWorldTransform::identity(),
-            world_content_transform: LayerToWorldTransform::identity(),
-            local_transform: *local_transform,
-            children: Vec::new(),
-            pipeline_id: pipeline_id,
-        }
-    }
-
-    pub fn add_child(&mut self, child: ScrollLayerId) {
-        self.children.push(child);
-    }
-
-    pub fn finalize(&mut self, scrolling: &ScrollingState) {
-        self.scrolling = *scrolling;
-    }
-
-    pub fn overscroll_amount(&self) -> LayerSize {
-        let scrollable_width = self.scrollable_width();
-        let overscroll_x = if self.scrolling.offset.x > 0.0 {
-            -self.scrolling.offset.x
-        } else if self.scrolling.offset.x < -scrollable_width {
-            -scrollable_width - self.scrolling.offset.x
-        } else {
-            0.0
-        };
-
-        let scrollable_height = self.scrollable_height();
-        let overscroll_y = if self.scrolling.offset.y > 0.0 {
-            -self.scrolling.offset.y
-        } else if self.scrolling.offset.y < -scrollable_height {
-            -scrollable_height - self.scrolling.offset.y
-        } else {
-            0.0
-        };
-
-        LayerSize::new(overscroll_x, overscroll_y)
-    }
-
-    pub fn set_scroll_origin(&mut self, origin: &LayerPoint) -> bool {
-        let scrollable_height = self.scrollable_height();
-        let scrollable_width = self.scrollable_width();
-        if scrollable_height <= 0. && scrollable_width <= 0. {
-            return false;
-        }
-
-        let new_offset = LayerPoint::new((-origin.x).max(-scrollable_width).min(0.0).round(),
-                                         (-origin.y).max(-scrollable_height).min(0.0).round());
-        if new_offset == self.scrolling.offset {
-            return false;
-        }
-
-        self.scrolling.offset = new_offset;
-        self.scrolling.bouncing_back = false;
-        self.scrolling.started_bouncing_back = false;
-        return true;
-    }
-
-    pub fn update_transform(&mut self,
-                            parent_world_transform: &ScrollToWorldTransform,
-                            parent_viewport_rect: &ScrollLayerRect) {
-        let inv_transform = match self.local_transform.inverse() {
-            Some(transform) => transform,
-            None => {
-                // If a transform function causes the current transformation matrix of an object
-                // to be non-invertible, the object and its content do not get displayed.
-                self.combined_local_viewport_rect = LayerRect::zero();
-                return;
-            }
-        };
-
-        let parent_viewport_rect_in_local_space = inv_transform.transform_rect(parent_viewport_rect)
-                                                               .translate(&-self.scrolling.offset);
-        let local_viewport_rect = self.local_viewport_rect.translate(&-self.scrolling.offset);
-        let viewport_rect = parent_viewport_rect_in_local_space.intersection(&local_viewport_rect)
-                                                               .unwrap_or(LayerRect::zero());
-
-        self.combined_local_viewport_rect = viewport_rect;
-        self.world_viewport_transform = parent_world_transform.pre_mul(&self.local_transform);
-        self.world_content_transform = self.world_viewport_transform
-                                                     .pre_translated(self.scrolling.offset.x,
-                                                                     self.scrolling.offset.y,
-                                                                     0.0);
-    }
-
-    pub fn scrollable_height(&self) -> f32 {
-        self.content_size.height - self.local_viewport_rect.size.height
-    }
-
-    pub fn scrollable_width(&self) -> f32 {
-        self.content_size.width - self.local_viewport_rect.size.width
-    }
-
-    pub fn scroll(&mut self, scroll_location: ScrollLocation, phase: ScrollEventPhase) -> bool {
-        if self.scrolling.started_bouncing_back && phase == ScrollEventPhase::Move(false) {
-            return false;
-        }
-
-        let mut delta = match scroll_location {
-            ScrollLocation::Delta(delta) => delta,
-            ScrollLocation::Start => {
-                if self.scrolling.offset.y.round() >= 0.0 {
-                    // Nothing to do on this layer.
-                    return false;
-                }
-
-                self.scrolling.offset.y = 0.0;
-                return true;
-            },
-            ScrollLocation::End => {
-                let end_pos = self.local_viewport_rect.size.height - self.content_size.height;
-
-                if self.scrolling.offset.y.round() <= end_pos {
-                    // Nothing to do on this layer.
-                    return false;
-                }
-
-                self.scrolling.offset.y = end_pos;
-                return true;
-            }
-        };
-
-        let overscroll_amount = self.overscroll_amount();
-        let overscrolling = CAN_OVERSCROLL && (overscroll_amount.width != 0.0 ||
-                                               overscroll_amount.height != 0.0);
-        if overscrolling {
-            if overscroll_amount.width != 0.0 {
-                delta.x /= overscroll_amount.width.abs()
-            }
-            if overscroll_amount.height != 0.0 {
-                delta.y /= overscroll_amount.height.abs()
-            }
-        }
-
-        let scrollable_width = self.scrollable_width();
-        let scrollable_height = self.scrollable_height();
-        let is_unscrollable = scrollable_width <= 0. && scrollable_height <= 0.;
-        let original_layer_scroll_offset = self.scrolling.offset;
-
-        if scrollable_width > 0. {
-            self.scrolling.offset.x = self.scrolling.offset.x + delta.x;
-            if is_unscrollable || !CAN_OVERSCROLL {
-                self.scrolling.offset.x =
-                    self.scrolling.offset.x.min(0.0).max(-scrollable_width).round();
-            }
-        }
-
-        if scrollable_height > 0. {
-            self.scrolling.offset.y = self.scrolling.offset.y + delta.y;
-            if is_unscrollable || !CAN_OVERSCROLL {
-                self.scrolling.offset.y =
-                    self.scrolling.offset.y.min(0.0).max(-scrollable_height).round();
-            }
-        }
-
-        if phase == ScrollEventPhase::Start || phase == ScrollEventPhase::Move(true) {
-            self.scrolling.started_bouncing_back = false
-        } else if overscrolling &&
-                ((delta.x < 1.0 && delta.y < 1.0) || phase == ScrollEventPhase::End) {
-            self.scrolling.started_bouncing_back = true;
-            self.scrolling.bouncing_back = true
-        }
-
-        if CAN_OVERSCROLL {
-            self.stretch_overscroll_spring();
-        }
-
-        self.scrolling.offset != original_layer_scroll_offset ||
-            self.scrolling.started_bouncing_back
-    }
-
-    pub fn stretch_overscroll_spring(&mut self) {
-        let overscroll_amount = self.overscroll_amount();
-        self.scrolling.spring.coords(self.scrolling.offset,
-                                     self.scrolling.offset,
-                                     self.scrolling.offset + overscroll_amount);
-    }
-
-    pub fn tick_scrolling_bounce_animation(&mut self) {
-        let finished = self.scrolling.spring.animate();
-        self.scrolling.offset = self.scrolling.spring.current();
-        if finished {
-            self.scrolling.bouncing_back = false
-        }
-    }
-
-    pub fn ray_intersects_layer(&self, cursor: &WorldPoint) -> bool {
-        let inv = self.world_viewport_transform.inverse().unwrap();
-        let z0 = -10000.0;
-        let z1 =  10000.0;
-
-        let p0 = inv.transform_point4d(&WorldPoint4D::new(cursor.x, cursor.y, z0, 1.0));
-        let p0 = Point3D::new(p0.x / p0.w,
-                              p0.y / p0.w,
-                              p0.z / p0.w);
-        let p1 = inv.transform_point4d(&WorldPoint4D::new(cursor.x, cursor.y, z1, 1.0));
-        let p1 = Point3D::new(p1.x / p1.w,
-                              p1.y / p1.w,
-                              p1.z / p1.w);
-
-        if self.scrollable_width() <= 0. && self.scrollable_height() <= 0. {
-            return false;
-        }
-        ray_intersects_rect(p0, p1, self.local_viewport_rect.to_untyped())
-    }
-}
-
-#[derive(Copy, Clone)]
-pub struct ScrollingState {
-    pub offset: LayerPoint,
-    pub spring: Spring,
-    pub started_bouncing_back: bool,
-    pub bouncing_back: bool,
-    pub should_handoff_scroll: bool
-}
-
-impl ScrollingState {
-    pub fn new() -> ScrollingState {
-        ScrollingState {
-            offset: LayerPoint::zero(),
-            spring: Spring::at(LayerPoint::zero(), STIFFNESS, DAMPING),
-            started_bouncing_back: false,
-            bouncing_back: false,
-            should_handoff_scroll: false
-        }
-    }
-}
-
--- a/gfx/webrender/src/lib.rs
+++ b/gfx/webrender/src/lib.rs
@@ -47,36 +47,36 @@ extern crate lazy_static;
 #[macro_use]
 extern crate log;
 #[macro_use]
 extern crate bitflags;
 #[macro_use]
 extern crate thread_profiler;
 
 mod batch_builder;
+mod clip_scroll_node;
+mod clip_scroll_tree;
 mod debug_colors;
 mod debug_font_data;
 mod debug_render;
 mod device;
 mod frame;
 mod frame_builder;
 mod freelist;
 mod geometry;
 mod gpu_store;
 mod internal_types;
-mod layer;
 mod mask_cache;
 mod prim_store;
 mod profiler;
 mod record;
 mod render_backend;
 mod render_task;
 mod resource_cache;
 mod scene;
-mod scroll_tree;
 mod spring;
 mod texture_cache;
 mod tiling;
 mod util;
 
 mod shader_source {
     include!(concat!(env!("OUT_DIR"), "/shaders.rs"));
 }
--- a/gfx/webrender/src/platform/windows/font.rs
+++ b/gfx/webrender/src/platform/windows/font.rs
@@ -77,28 +77,34 @@ fn dwrite_render_mode(font_face: &dwrote
         return dwrote::DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
     }
 
     dwrite_render_mode
 }
 
 fn get_glyph_dimensions_with_analysis(analysis: dwrote::GlyphRunAnalysis,
                                       texture_type: dwrote::DWRITE_TEXTURE_TYPE)
-                                      -> GlyphDimensions {
+                                      -> Option<GlyphDimensions> {
     let bounds = analysis.get_alpha_texture_bounds(texture_type);
 
     let width = (bounds.right - bounds.left) as u32;
     let height = (bounds.bottom - bounds.top) as u32;
-    assert!(width > 0 && height > 0);
-    GlyphDimensions {
+
+    // Alpha texture bounds can sometimes return an empty rect
+    // Such as for spaces
+    if width == 0 || height == 0 {
+        return None
+    }
+
+    Some(GlyphDimensions {
         left: bounds.left,
         top: -bounds.top,
         width: width,
         height: height,
-    }
+    })
 }
 
 impl FontContext {
     pub fn new() -> FontContext {
         // These are the default values we use in Gecko.
         // We use a gamma value of 2.3 for gdi fonts
         // TODO: Fetch this data from Gecko itself.
         let contrast = 1.0;
@@ -198,17 +204,17 @@ impl FontContext {
     pub fn get_glyph_dimensions(&self,
                                 key: &GlyphKey)
                                 -> Option<GlyphDimensions> {
         // Probably have to default to something else here.
         let render_mode = FontRenderMode::Subpixel;
         let analysis = self.create_glyph_analysis(key, render_mode, None);
 
         let texture_type = dwrite_texture_type(render_mode);
-        Some(get_glyph_dimensions_with_analysis(analysis, texture_type))
+        get_glyph_dimensions_with_analysis(analysis, texture_type)
     }
 
     // DWRITE gives us values in RGB. WR doesn't really touch it after. Note, CG returns in BGR
     // TODO: Decide whether all fonts should return RGB or BGR
     fn convert_to_rgba(&self, pixels: &Vec<u8>, render_mode: FontRenderMode) -> Vec<u8> {
         match render_mode {
             FontRenderMode::Mono => {
                 let mut rgba_pixels: Vec<u8> = vec![0; pixels.len() * 4];
@@ -261,16 +267,20 @@ impl FontContext {
                                                   render_mode,
                                                   glyph_options);
         let texture_type = dwrite_texture_type(render_mode);
 
         let bounds = analysis.get_alpha_texture_bounds(texture_type);
         let width = (bounds.right - bounds.left) as usize;
         let height = (bounds.bottom - bounds.top) as usize;
 
+        // We should not get here since glyph_dimensions would return
+        // None for empty glyphs.
+        assert!(width > 0 && height > 0);
+
         let mut pixels = analysis.create_alpha_texture(texture_type, bounds);
 
         let lut_correction = match glyph_options {
             Some(option) => {
                 if option.force_gdi_rendering {
                     &self.gdi_gamma_lut
                 } else {
                     &self.gamma_lut
--- a/gfx/webrender/src/prim_store.rs
+++ b/gfx/webrender/src/prim_store.rs
@@ -25,31 +25,40 @@ use webrender_traits::{ExtendMode, Gradi
 pub const CLIP_DATA_GPU_SIZE: usize = 5;
 pub const MASK_DATA_GPU_SIZE: usize = 1;
 
 /// Stores two coordinates in texel space. The coordinates
 /// are stored in texel coordinates because the texture atlas
 /// may grow. Storing them as texel coords and normalizing
 /// the UVs in the vertex shader means nothing needs to be
 /// updated on the CPU when the texture size changes.
-#[derive(Clone)]
+#[derive(Copy, Clone, Debug)]
 pub struct TexelRect {
     pub uv0: DevicePoint,
     pub uv1: DevicePoint,
 }
 
 impl Default for TexelRect {
     fn default() -> TexelRect {
         TexelRect {
             uv0: DevicePoint::zero(),
             uv1: DevicePoint::zero(),
         }
     }
 }
 
+impl TexelRect {
+    pub fn new(u0: u32, v0: u32, u1: u32, v1: u32) -> TexelRect {
+        TexelRect {
+            uv0: DevicePoint::new(u0 as f32, v0 as f32),
+            uv1: DevicePoint::new(u1 as f32, v1 as f32),
+        }
+    }
+}
+
 /// For external images, it's not possible to know the
 /// UV coords of the image (or the image data itself)
 /// until the render thread receives the frame and issues
 /// callbacks to the client application. For external
 /// images that are visible, a DeferredResolve is created
 /// that is stored in the frame. This allows the render
 /// thread to iterate this list and update any changed
 /// texture data and update the UV rect.
@@ -131,16 +140,17 @@ pub enum ImagePrimitiveKind {
     WebGL(WebGLContextId),
 }
 
 #[derive(Debug)]
 pub struct ImagePrimitiveCpu {
     pub kind: ImagePrimitiveKind,
     pub color_texture_id: SourceTexture,
     pub resource_address: GpuStoreAddress,
+    pub sub_rect: Option<TexelRect>,
 }
 
 #[derive(Debug, Clone)]
 #[repr(C)]
 pub struct ImagePrimitiveGpu {
     pub stretch_size: LayerSize,
     pub tile_spacing: LayerSize,
 }
@@ -915,18 +925,28 @@ impl PrimitiveStore {
                         ImagePrimitiveKind::WebGL(context_id) => {
                             let cache_item = resource_cache.get_webgl_texture(&context_id);
                             (cache_item.texture_id, Some(cache_item))
                         }
                     };
 
                     if let Some(cache_item) = cache_item {
                         let resource_rect = self.gpu_resource_rects.get_mut(image_cpu.resource_address);
-                        resource_rect.uv0 = cache_item.uv0;
-                        resource_rect.uv1 = cache_item.uv1;
+                        match image_cpu.sub_rect {
+                            Some(sub_rect) => {
+                                resource_rect.uv0.x = cache_item.uv0.x + sub_rect.uv0.x;
+                                resource_rect.uv0.y = cache_item.uv0.y + sub_rect.uv0.y;
+                                resource_rect.uv1.x = cache_item.uv0.x + sub_rect.uv1.x;
+                                resource_rect.uv1.y = cache_item.uv0.y + sub_rect.uv1.y;
+                            }
+                            None => {
+                                resource_rect.uv0 = cache_item.uv0;
+                                resource_rect.uv1 = cache_item.uv1;
+                            }
+                        }
                     }
                     image_cpu.color_texture_id = texture_id;
                 }
                 PrimitiveKind::YuvImage => {
                     let image_cpu = &mut self.cpu_yuv_images[metadata.cpu_prim_index.0];
                     let image_gpu: &mut YuvImagePrimitiveGpu = unsafe {
                         mem::transmute(self.gpu_data64.get_mut(metadata.gpu_prim_index))
                     };
--- a/gfx/webrender/src/record.rs
+++ b/gfx/webrender/src/record.rs
@@ -1,14 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use bincode::serde::serialize;
-use bincode;
+use bincode::{SizeLimit, serialize};
 use std::fmt::Debug;
 use std::mem;
 use std::any::TypeId;
 use std::fs::File;
 use std::io::Write;
 use std::path::PathBuf;
 use webrender_traits::ApiMsg;
 use byteorder::{LittleEndian, WriteBytesExt};
@@ -46,17 +45,17 @@ impl BinaryRecorder {
         self.file.write_u32::<LittleEndian>(data.len() as u32).ok();
         self.file.write(data).ok();
     }
 }
 
 impl ApiRecordingReceiver for BinaryRecorder {
     fn write_msg(&mut self, _: u32, msg: &ApiMsg) {
         if should_record_msg(msg) {
-            let buf = serialize(msg, bincode::SizeLimit::Infinite).unwrap();
+            let buf = serialize(msg, SizeLimit::Infinite).unwrap();
             self.write_length_and_data(&buf);
         }
     }
 
     fn write_payload(&mut self, _: u32, data: &[u8]) {
         // signal payload with a 0 length
         self.file.write_u32::<LittleEndian>(0).ok();
         self.write_length_and_data(data);
--- a/gfx/webrender/src/render_backend.rs
+++ b/gfx/webrender/src/render_backend.rs
@@ -16,17 +16,17 @@ use std::io::{Cursor, Read};
 use std::sync::{Arc, Mutex};
 use std::sync::mpsc::Sender;
 use texture_cache::TextureCache;
 use thread_profiler::register_thread_with_profiler;
 use threadpool::ThreadPool;
 use webrender_traits::{ApiMsg, AuxiliaryLists, BuiltDisplayList, IdNamespace, ImageData};
 use webrender_traits::{PipelineId, RenderNotifier, RenderDispatcher, WebGLCommand, WebGLContextId};
 use webrender_traits::channel::{PayloadHelperMethods, PayloadReceiver, PayloadSender, MsgReceiver};
-use webrender_traits::{VRCompositorCommand, VRCompositorHandler};
+use webrender_traits::{BlobImageRenderer, VRCompositorCommand, VRCompositorHandler};
 use offscreen_gl_context::GLContextDispatcher;
 
 /// The render backend is responsible for transforming high level display lists into
 /// GPU-friendly work which is then submitted to the renderer in the form of a frame::Frame.
 ///
 /// The render backend operates on its own thread.
 pub struct RenderBackend {
     api_rx: MsgReceiver<ApiMsg>,
@@ -63,19 +63,20 @@ impl RenderBackend {
                texture_cache: TextureCache,
                enable_aa: bool,
                workers: Arc<Mutex<ThreadPool>>,
                notifier: Arc<Mutex<Option<Box<RenderNotifier>>>>,
                webrender_context_handle: Option<GLContextHandleWrapper>,
                config: FrameBuilderConfig,
                recorder: Option<Box<ApiRecordingReceiver>>,
                main_thread_dispatcher: Arc<Mutex<Option<Box<RenderDispatcher>>>>,
+               blob_image_renderer: Option<Box<BlobImageRenderer>>,
                vr_compositor_handler: Arc<Mutex<Option<Box<VRCompositorHandler>>>>) -> RenderBackend {
 
-        let resource_cache = ResourceCache::new(texture_cache, workers, enable_aa);
+        let resource_cache = ResourceCache::new(texture_cache, workers, blob_image_renderer, enable_aa);
 
         register_thread_with_profiler("Backend".to_string());
 
         RenderBackend {
             api_rx: api_rx,
             payload_rx: payload_rx,
             payload_tx: payload_tx,
             result_tx: result_tx,
@@ -226,17 +227,17 @@ impl RenderBackend {
                                     self.notify_compositor_of_new_scroll_frame(true)
                                 }
                                 None => self.notify_compositor_of_new_scroll_frame(false),
                             }
                         }
                         ApiMsg::ScrollLayersWithScrollId(origin, pipeline_id, scroll_root_id) => {
                             profile_scope!("ScrollLayersWithScrollId");
                             let frame = profile_counters.total_time.profile(|| {
-                                if self.frame.scroll_layers(origin, pipeline_id, scroll_root_id) {
+                                if self.frame.scroll_nodes(origin, pipeline_id, scroll_root_id) {
                                     Some(self.render())
                                 } else {
                                     None
                                 }
                             });
 
                             match frame {
                                 Some(frame) => {
@@ -256,17 +257,17 @@ impl RenderBackend {
 
                             self.publish_frame_and_notify_compositor(frame, &mut profile_counters);
                         }
                         ApiMsg::TranslatePointToLayerSpace(..) => {
                             panic!("unused api - remove from webrender_traits");
                         }
                         ApiMsg::GetScrollLayerState(tx) => {
                             profile_scope!("GetScrollLayerState");
-                            tx.send(self.frame.get_scroll_layer_state())
+                            tx.send(self.frame.get_scroll_node_state())
                               .unwrap()
                         }
                         ApiMsg::RequestWebGLContext(size, attributes, tx) => {
                             if let Some(ref wrapper) = self.webrender_context_handle {
                                 let dispatcher: Option<Box<GLContextDispatcher>> = if cfg!(target_os = "windows") {
                                     Some(Box::new(WebRenderGLDispatcher {
                                         dispatcher: self.main_thread_dispatcher.clone()
                                     }))
--- a/gfx/webrender/src/render_task.rs
+++ b/gfx/webrender/src/render_task.rs
@@ -1,18 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use internal_types::{HardwareCompositeOp, LowLevelFilterOp};
 use mask_cache::MaskCacheInfo;
 use prim_store::{PrimitiveCacheKey, PrimitiveIndex};
 use std::{cmp, f32, i32, mem, usize};
-use tiling::{PackedLayerIndex, RenderPass, RenderTargetIndex, ScrollLayerIndex};
-use tiling::StackingContextIndex;
+use tiling::{ClipScrollGroupIndex, PackedLayerIndex, RenderPass, RenderTargetIndex};
+use tiling::{ScrollLayerIndex, StackingContextIndex};
 use webrender_traits::{DeviceIntLength, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
 use webrender_traits::MixBlendMode;
 
 const FLOATS_PER_RENDER_TASK_INFO: usize = 12;
 
 #[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
 pub struct RenderTaskIndex(pub usize);
 
@@ -46,17 +46,17 @@ pub enum RenderTaskId {
 #[derive(Debug, Clone)]
 pub enum RenderTaskLocation {
     Fixed,
     Dynamic(Option<(DeviceIntPoint, RenderTargetIndex)>, DeviceIntSize),
 }
 
 #[derive(Debug, Clone)]
 pub enum AlphaRenderItem {
-    Primitive(StackingContextIndex, PrimitiveIndex, i32),
+    Primitive(ClipScrollGroupIndex, PrimitiveIndex, i32),
     Blend(StackingContextIndex, RenderTaskId, LowLevelFilterOp, i32),
     Composite(StackingContextIndex, RenderTaskId, RenderTaskId, MixBlendMode, i32),
     HardwareComposite(StackingContextIndex, RenderTaskId, HardwareCompositeOp, i32),
 }
 
 #[derive(Debug, Clone)]
 pub struct AlphaRenderTask {
     screen_origin: DeviceIntPoint,
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -43,17 +43,17 @@ use threadpool::ThreadPool;
 use tiling::{AlphaBatchKind, BlurCommand, Frame, PrimitiveBatch, PrimitiveBatchData};
 use tiling::{CacheClipInstance, PrimitiveInstance, RenderTarget};
 use time::precise_time_ns;
 use thread_profiler::{register_thread_with_profiler, write_profile};
 use util::TransformedRectKind;
 use webrender_traits::{ColorF, Epoch, PipelineId, RenderNotifier, RenderDispatcher};
 use webrender_traits::{ExternalImageId, ImageData, ImageFormat, RenderApiSender, RendererKind};
 use webrender_traits::{DeviceIntRect, DevicePoint, DeviceIntPoint, DeviceIntSize, DeviceUintSize};
-use webrender_traits::ImageDescriptor;
+use webrender_traits::{ImageDescriptor, BlobImageRenderer};
 use webrender_traits::channel;
 use webrender_traits::VRCompositorHandler;
 
 pub const GPU_DATA_TEXTURE_POOL: usize = 5;
 pub const MAX_VERTEX_TEXTURE_WIDTH: usize = 1024;
 
 const GPU_TAG_CACHE_BOX_SHADOW: GpuProfileTag = GpuProfileTag { label: "C_BoxShadow", color: debug_colors::BLACK };
 const GPU_TAG_CACHE_CLIP: GpuProfileTag = GpuProfileTag { label: "C_Clip", color: debug_colors::PURPLE };
@@ -458,16 +458,21 @@ pub struct Renderer {
     /// by the backend thread / texture cache. We free the
     /// texture memory associated with a TextureId when its
     /// texture cache ID is freed by the texture cache, but
     /// reuse the TextureId when the texture caches's free
     /// list reuses the texture cache ID. This saves having to
     /// use a hashmap, and allows a flat vector for performance.
     cache_texture_id_map: Vec<TextureId>,
 
+    /// A special 1x1 dummy cache texture used for shaders that expect to work
+    /// with the cache but are actually running in the first pass
+    /// when no target is yet provided as a cache texture input.
+    dummy_cache_texture_id: TextureId,
+
     /// Optional trait object that allows the client
     /// application to provide external buffers for image data.
     external_image_handler: Option<Box<ExternalImageHandler>>,
 
     /// Map of external image IDs to native textures.
     external_images: HashMap<ExternalImageId, TextureId, BuildHasherDefault<FnvHasher>>,
 
     // Optional trait object that handles WebVR commands.
@@ -670,17 +675,20 @@ impl Renderer {
         let ps_hw_composite = try!{
             LazilyCompiledShader::new(ShaderKind::Primitive,
                                      "ps_hardware_composite",
                                      &[],
                                      &mut device,
                                      options.precache_shaders)
         };
 
-        let mut texture_cache = TextureCache::new();
+        let device_max_size = device.max_texture_size();
+        let max_texture_size = cmp::min(device_max_size, options.max_texture_size.unwrap_or(device_max_size));
+
+        let mut texture_cache = TextureCache::new(max_texture_size);
 
         let white_pixels: Vec<u8> = vec![
             0xff, 0xff, 0xff, 0xff,
             0xff, 0xff, 0xff, 0xff,
             0xff, 0xff, 0xff, 0xff,
             0xff, 0xff, 0xff, 0xff,
         ];
         let mask_pixels: Vec<u8> = vec![
@@ -707,16 +715,25 @@ impl Renderer {
                                 height: 2,
                                 stride: None,
                                 format: ImageFormat::A8,
                                 is_opaque: false,
                              },
                              TextureFilter::Linear,
                              ImageData::Raw(Arc::new(mask_pixels)));
 
+        let dummy_cache_texture_id = device.create_texture_ids(1, TextureTarget::Array)[0];
+        device.init_texture(dummy_cache_texture_id,
+                            1,
+                            1,
+                            ImageFormat::RGBA8,
+                            TextureFilter::Linear,
+                            RenderTargetMode::LayerRenderTarget(1),
+                            None);
+
         let debug_renderer = DebugRenderer::new(&mut device);
 
         let gpu_data_textures = [
             GpuDataTextures::new(&mut device),
             GpuDataTextures::new(&mut device),
             GpuDataTextures::new(&mut device),
             GpuDataTextures::new(&mut device),
             GpuDataTextures::new(&mut device),
@@ -775,30 +792,33 @@ impl Renderer {
         let (device_pixel_ratio, enable_aa) = (options.device_pixel_ratio, options.enable_aa);
         let render_target_debug = options.render_target_debug;
         let payload_tx_for_backend = payload_tx.clone();
         let recorder = options.recorder;
         let workers = options.workers.take().unwrap_or_else(||{
             // TODO(gw): Use a heuristic to select best # of worker threads.
             Arc::new(Mutex::new(ThreadPool::new_with_name("WebRender:Worker".to_string(), 4)))
         });
+
+        let blob_image_renderer = options.blob_image_renderer.take();
         try!{ thread::Builder::new().name("RenderBackend".to_string()).spawn(move || {
             let mut backend = RenderBackend::new(api_rx,
                                                  payload_rx,
                                                  payload_tx_for_backend,
                                                  result_tx,
                                                  device_pixel_ratio,
                                                  texture_cache,
                                                  enable_aa,
                                                  workers,
                                                  backend_notifier,
                                                  context_handle,
                                                  config,
                                                  recorder,
                                                  backend_main_thread_dispatcher,
+                                                 blob_image_renderer,
                                                  backend_vr_compositor);
             backend.run();
         })};
 
         let renderer = Renderer {
             result_rx: result_rx,
             device: device,
             current_frame: None,
@@ -839,16 +859,17 @@ impl Renderer {
             prim_vao_id: prim_vao_id,
             blur_vao_id: blur_vao_id,
             clip_vao_id: clip_vao_id,
             gdt_index: 0,
             gpu_data_textures: gpu_data_textures,
             pipeline_epoch_map: HashMap::with_hasher(Default::default()),
             main_thread_dispatcher: main_thread_dispatcher,
             cache_texture_id_map: Vec::new(),
+            dummy_cache_texture_id: dummy_cache_texture_id,
             external_image_handler: None,
             external_images: HashMap::with_hasher(Default::default()),
             vr_compositor_handler: vr_compositor
         };
 
         let sender = RenderApiSender::new(api_tx, payload_tx);
         Ok((renderer, sender))
     }
@@ -1158,17 +1179,17 @@ impl Renderer {
         self.profile_counters.vertices.add(6 * data.len());
         self.profile_counters.draw_calls.inc();
     }
 
     fn submit_batch(&mut self,
                     batch: &PrimitiveBatch,
                     projection: &Matrix4D<f32>,
                     render_task_data: &Vec<RenderTaskData>,
-                    cache_texture: Option<TextureId>,
+                    cache_texture: TextureId,
                     render_target: Option<(TextureId, i32)>,
                     target_dimensions: DeviceUintSize) {
         let transform_kind = batch.key.flags.transform_kind();
         let needs_clipping = batch.key.flags.needs_clipping();
         debug_assert!(!needs_clipping || batch.key.blend_mode == BlendMode::Alpha);
 
         match batch.data {
             PrimitiveBatchData::Instances(ref data) => {
@@ -1251,28 +1272,27 @@ impl Renderer {
                 // on pulling specific values from the render target data
                 // and also cloning the single primitive instance to be
                 // able to pass to draw_instanced_batch(). We should
                 // think about a cleaner way to achieve this!
 
                 // Before submitting the composite batch, do the
                 // framebuffer readbacks that are needed for each
                 // composite operation in this batch.
-                let cache_texture_id = cache_texture.unwrap();
-                let cache_texture_dimensions = self.device.get_texture_dimensions(cache_texture_id);
+                let cache_texture_dimensions = self.device.get_texture_dimensions(cache_texture);
 
                 let backdrop = &render_task_data[instance.task_index as usize];
                 let readback = &render_task_data[instance.user_data[0] as usize];
                 let source = &render_task_data[instance.user_data[1] as usize];
 
                 // Bind the FBO to blit the backdrop to.
                 // Called per-instance in case the layer (and therefore FBO)
                 // changes. The device will skip the GL call if the requested
                 // target is already bound.
-                let cache_draw_target = (cache_texture_id, readback.data[4] as i32);
+                let cache_draw_target = (cache_texture, readback.data[4] as i32);
                 self.device.bind_draw_target(Some(cache_draw_target), Some(cache_texture_dimensions));
 
                 let src_x = backdrop.data[0] - backdrop.data[4] + source.data[4];
                 let src_y = backdrop.data[1] - backdrop.data[5] + source.data[5];
 
                 let dest_x = readback.data[0];
                 let dest_y = readback.data[1];
 
@@ -1309,32 +1329,30 @@ impl Renderer {
             }
         }
     }
 
     fn draw_target(&mut self,
                    render_target: Option<(TextureId, i32)>,
                    target: &RenderTarget,
                    target_size: DeviceUintSize,
-                   cache_texture: Option<TextureId>,
+                   cache_texture: TextureId,
                    should_clear: bool,
                    background_color: Option<ColorF>,
                    render_task_data: &Vec<RenderTaskData>) {
         self.device.disable_depth();
         self.device.enable_depth_write();
 
         let projection = {
             let _gm = self.gpu_profile.add_marker(GPU_TAG_SETUP_TARGET);
             self.device.bind_draw_target(render_target, Some(target_size));
 
             self.device.set_blend(false);
             self.device.set_blend_mode_alpha();
-            if let Some(cache_texture) = cache_texture {
-                self.device.bind_texture(TextureSampler::Cache, cache_texture);
-            }
+            self.device.bind_texture(TextureSampler::Cache, cache_texture);
 
             let (color, projection) = match render_target {
                 Some(..) => (
                     // The clear color here is chosen specifically such that:
                     // - The red channel is cleared to 1, so that the clip mask
                     //   generation (which reads/writes the red channel) can
                     //   assume that each allocated rect is opaque / non-clipped
                     //   initially.
@@ -1627,17 +1645,17 @@ impl Renderer {
 
             // TODO(gw): This is a hack / workaround for #728.
             // We should find a better way to implement these updates rather
             // than wasting this extra memory, but for now it removes a large
             // number of driver stalls.
             self.gpu_data_textures[self.gdt_index].init_frame(&mut self.device, frame);
             self.gdt_index = (self.gdt_index + 1) % GPU_DATA_TEXTURE_POOL;
 
-            let mut src_id = None;
+            let mut src_id = self.dummy_cache_texture_id;
 
             for (pass_index, pass) in frame.passes.iter().enumerate() {
                 let (do_clear, size, target_id) = if pass.is_framebuffer {
                     (self.clear_framebuffer || needs_clear,
                      framebuffer_size,
                      None)
                 } else {
                     (true, &frame.cache_size, Some(self.render_targets[pass_index]))
@@ -1652,17 +1670,17 @@ impl Renderer {
                                      *size,
                                      src_id,
                                      do_clear,
                                      frame.background_color,
                                      &frame.render_task_data);
 
                 }
 
-                src_id = target_id;
+                src_id = target_id.unwrap_or(self.dummy_cache_texture_id);
             }
 
             self.draw_render_target_debug(framebuffer_size);
         }
 
         self.unlock_external_images();
     }
 
@@ -1711,16 +1729,24 @@ impl Renderer {
                                                    None,
                                                    dest_rect);
 
                     current_target += 1;
                 }
             }
         }
     }
+
+    // De-initialize the Renderer safely, assuming the GL is still alive and active.
+    pub fn deinit(mut self) {
+        //Note: this is a fake frame, only needed because texture deletion is require to happen inside a frame
+        self.device.begin_frame(1.0);
+        self.device.deinit_texture(self.dummy_cache_texture_id);
+        self.device.end_frame();
+    }
 }
 
 pub enum ExternalImageSource<'a> {
     RawData(&'a [u8]),      // raw buffers.
     NativeTexture(u32),     // Is a gl::GLuint texture handle
 }
 
 /// The data that an external client should provide about
@@ -1751,31 +1777,32 @@ pub trait ExternalImageHandler {
     fn lock(&mut self, key: ExternalImageId) -> ExternalImage;
     /// Unlock the external image. The WR should not read the image content
     /// after this call.
     fn unlock(&mut self, key: ExternalImageId);
     /// Tell the WR client that it could start to release this external image.
     fn release(&mut self, key: ExternalImageId);
 }
 
-#[derive(Debug)]
 pub struct RendererOptions {
     pub device_pixel_ratio: f32,
     pub resource_override_path: Option<PathBuf>,
     pub enable_aa: bool,
     pub enable_profiler: bool,
     pub debug: bool,
     pub enable_scrollbars: bool,
     pub precache_shaders: bool,
     pub renderer_kind: RendererKind,
     pub enable_subpixel_aa: bool,
     pub clear_framebuffer: bool,
     pub clear_color: ColorF,
     pub render_target_debug: bool,
+    pub max_texture_size: Option<u32>,
     pub workers: Option<Arc<Mutex<ThreadPool>>>,
+    pub blob_image_renderer: Option<Box<BlobImageRenderer>>,
     pub recorder: Option<Box<ApiRecordingReceiver>>,
 }
 
 impl Default for RendererOptions {
     fn default() -> RendererOptions {
         RendererOptions {
             device_pixel_ratio: 1.0,
             resource_override_path: None,
@@ -1784,13 +1811,15 @@ impl Default for RendererOptions {
             debug: false,
             enable_scrollbars: false,
             precache_shaders: false,
             renderer_kind: RendererKind::Native,
             enable_subpixel_aa: false,
             clear_framebuffer: true,
             clear_color: ColorF::new(1.0, 1.0, 1.0, 1.0),
             render_target_debug: false,
+            max_texture_size: None,
             workers: None,
+            blob_image_renderer: None,
             recorder: None,
         }
     }
 }
--- a/gfx/webrender/src/resource_cache.rs
+++ b/gfx/webrender/src/resource_cache.rs
@@ -19,16 +19,17 @@ use std::sync::{Arc, Barrier, Mutex};
 use std::sync::mpsc::{channel, Receiver, Sender};
 use std::thread;
 use texture_cache::{TextureCache, TextureCacheItemId};
 use thread_profiler::register_thread_with_profiler;
 use webrender_traits::{Epoch, FontKey, GlyphKey, ImageKey, ImageFormat, ImageRendering};
 use webrender_traits::{FontRenderMode, ImageData, GlyphDimensions, WebGLContextId};
 use webrender_traits::{DevicePoint, DeviceIntSize, ImageDescriptor, ColorF};
 use webrender_traits::{ExternalImageId, GlyphOptions, GlyphInstance};
+use webrender_traits::{BlobImageRenderer, BlobImageDescriptor, BlobImageError};
 use threadpool::ThreadPool;
 use euclid::Point2D;
 
 thread_local!(pub static FONT_CONTEXT: RefCell<FontContext> = RefCell::new(FontContext::new()));
 
 type GlyphCache = ResourceClassCache<RenderedGlyphKey, Option<TextureCacheItemId>>;
 
 /// Message sent from the resource cache to the glyph cache thread.
@@ -204,21 +205,25 @@ pub struct ResourceCache {
     texture_cache: TextureCache,
 
     // TODO(gw): We should expire (parts of) this cache semi-regularly!
     cached_glyph_dimensions: HashMap<GlyphKey, Option<GlyphDimensions>, BuildHasherDefault<FnvHasher>>,
     pending_image_requests: Vec<ImageRequest>,
     glyph_cache_tx: Sender<GlyphCacheMsg>,
     glyph_cache_result_queue: Receiver<GlyphCacheResultMsg>,
     pending_external_image_update_list: ExternalImageUpdateList,
+
+    blob_image_renderer: Option<Box<BlobImageRenderer>>,
+    blob_image_requests: HashSet<ImageRequest>,
 }
 
 impl ResourceCache {
     pub fn new(texture_cache: TextureCache,
                workers: Arc<Mutex<ThreadPool>>,
+               blob_image_renderer: Option<Box<BlobImageRenderer>>,
                enable_aa: bool) -> ResourceCache {
         let (glyph_cache_tx, glyph_cache_result_queue) = spawn_glyph_cache_thread(workers);
 
         ResourceCache {
             cached_glyphs: Some(ResourceClassCache::new()),
             cached_images: ResourceClassCache::new(),
             webgl_textures: HashMap::with_hasher(Default::default()),
             font_templates: HashMap::with_hasher(Default::default()),
@@ -227,32 +232,45 @@ impl ResourceCache {
             texture_cache: texture_cache,
             state: State::Idle,
             enable_aa: enable_aa,
             current_frame_id: FrameId(0),
             pending_image_requests: Vec::new(),
             glyph_cache_tx: glyph_cache_tx,
             glyph_cache_result_queue: glyph_cache_result_queue,
             pending_external_image_update_list: ExternalImageUpdateList::new(),
+
+            blob_image_renderer: blob_image_renderer,
+            blob_image_requests: HashSet::new(),
         }
     }
 
+    pub fn max_texture_size(&self) -> u32 {
+        self.texture_cache.max_texture_size()
+    }
+
     pub fn add_font_template(&mut self, font_key: FontKey, template: FontTemplate) {
         // Push the new font to the glyph cache thread, and also store
         // it locally for glyph metric requests.
         self.glyph_cache_tx
             .send(GlyphCacheMsg::AddFont(font_key, template.clone()))
             .unwrap();
         self.font_templates.insert(font_key, template);
     }
 
     pub fn add_image_template(&mut self,
                               image_key: ImageKey,
                               descriptor: ImageDescriptor,
                               data: ImageData) {
+        if descriptor.width > self.max_texture_size() || descriptor.height > self.max_texture_size() {
+            // TODO: we need to support handle this case gracefully, cf. issue #620.
+            println!("Warning: texture size ({} {}) larger than the maximum size",
+                     descriptor.width, descriptor.height);
+        }
+
         let resource = ImageResource {
             descriptor: descriptor,
             data: data,
             epoch: Epoch(0),
         };
 
         self.image_templates.insert(image_key, resource);
     }
@@ -316,24 +334,48 @@ impl ResourceCache {
     pub fn update_webgl_texture(&mut self, id: WebGLContextId, texture_id: SourceTexture, size: DeviceIntSize) {
         let webgl_texture = self.webgl_textures.get_mut(&id).unwrap();
 
         // Update new texture id and size
         webgl_texture.id = texture_id;
         webgl_texture.size = size;
     }
 
-    pub fn request_image(&mut self,
-                         key: ImageKey,
-                         rendering: ImageRendering) {
+    pub fn request_image(&mut self, key: ImageKey, rendering: ImageRendering) {
         debug_assert!(self.state == State::AddResources);
-        self.pending_image_requests.push(ImageRequest {
+        let request = ImageRequest {
             key: key,
             rendering: rendering,
-        });
+        };
+
+        let template = self.image_templates.get(&key).unwrap();
+        if let ImageData::Blob(ref data) = template.data {
+            if let Some(ref mut renderer) = self.blob_image_renderer {
+                let same_epoch = match self.cached_images.resources.get(&request) {
+                    Some(entry) => entry.epoch == template.epoch,
+                    None => false,
+                };
+
+                if !same_epoch && self.blob_image_requests.insert(request) {
+                    renderer.request_blob_image(
+                        key,
+                        data.clone(),
+                        &BlobImageDescriptor {
+                            width: template.descriptor.width,
+                            height: template.descriptor.height,
+                            format: template.descriptor.format,
+                            // TODO(nical): figure out the scale factor (should change with zoom).
+                            scale_factor: 1.0,
+                        },
+                    );
+                }
+            }
+        } else {
+            self.pending_image_requests.push(request);
+        }
     }
 
     pub fn request_glyphs(&mut self,
                           key: FontKey,
                           size: Au,
                           color: ColorF,
                           glyph_instances: &[GlyphInstance],
                           render_mode: FontRenderMode,
@@ -448,17 +490,17 @@ impl ResourceCache {
     }
 
     pub fn get_image_properties(&self, image_key: ImageKey) -> ImageProperties {
         let image_template = &self.image_templates[&image_key];
 
         let external_id = match image_template.data {
             ImageData::ExternalHandle(id) => Some(id),
             // raw and externalBuffer are all use resource_cache.
-            ImageData::Raw(..) | ImageData::ExternalBuffer(..) => None,
+            ImageData::Raw(..) | ImageData::ExternalBuffer(..) | ImageData::Blob(..) => None,
         };
 
         ImageProperties {
             descriptor: image_template.descriptor,
             external_id: external_id,
         }
     }
 
@@ -534,61 +576,95 @@ impl ResourceCache {
                     }
 
                     self.cached_glyphs = Some(cache);
                     break;
                 }
             }
         }
 
-        for request in self.pending_image_requests.drain(..) {
-            let cached_images = &mut self.cached_images;
-            let image_template = &self.image_templates[&request.key];
-            let image_data = image_template.data.clone();
-
-            match image_template.data {
-                ImageData::ExternalHandle(..) => {
-                    // external handle doesn't need to update the texture_cache.
-                }
-                ImageData::Raw(..) | ImageData::ExternalBuffer(..) => {
-                    match cached_images.entry(request.clone(), self.current_frame_id) {
-                        Occupied(entry) => {
-                            let image_id = entry.get().texture_cache_id;
-
-                            if entry.get().epoch != image_template.epoch {
-                                self.texture_cache.update(image_id,
-                                                          image_template.descriptor,
-                                                          image_data);
+        let mut image_requests = mem::replace(&mut self.pending_image_requests, Vec::new());
+        for request in image_requests.drain(..) {
+            self.finalize_image_request(request, None);
+        }
 
-                                // Update the cached epoch
-                                *entry.into_mut() = CachedImageInfo {
-                                    texture_cache_id: image_id,
-                                    epoch: image_template.epoch,
-                                };
-                            }
-                        }
-                        Vacant(entry) => {
-                            let image_id = self.texture_cache.new_item_id();
+        let mut blob_image_requests = mem::replace(&mut self.blob_image_requests, HashSet::new());
+        if self.blob_image_renderer.is_some() {
+            for request in blob_image_requests.drain() {
+                match self.blob_image_renderer.as_mut().unwrap()
+                                                .resolve_blob_image(request.key) {
+                    Ok(image) => {
+                        self.finalize_image_request(request, Some(ImageData::new(image.data)));
+                    }
+                    // TODO(nical): I think that we should handle these somewhat gracefully,
+                    // at least in the out-of-memory scenario.
+                    Err(BlobImageError::Oom) => {
+                        // This one should be recoverable-ish.
+                        panic!("Failed to render a vector image (OOM)");
+                    }
+                    Err(BlobImageError::InvalidKey) => {
+                        panic!("Invalid vector image key");
+                    }
+                    Err(BlobImageError::InvalidData) => {
+                        // TODO(nical): If we run into this we should kill the content process.
+                        panic!("Invalid vector image data");
+                    }
+                    Err(BlobImageError::Other(msg)) => {
+                        panic!("Vector image error {}", msg);
+                    }
+                }
+            }
+        }
+    }
 
-                            let filter = match request.rendering {
-                                ImageRendering::Pixelated => TextureFilter::Nearest,
-                                ImageRendering::Auto | ImageRendering::CrispEdges => TextureFilter::Linear,
-                            };
+    fn finalize_image_request(&mut self, request: ImageRequest, image_data: Option<ImageData>) {
+        let image_template = &self.image_templates[&request.key];
+        let image_data = image_data.unwrap_or_else(||{
+            image_template.data.clone()
+        });
 
-                            self.texture_cache.insert(image_id,
+        match image_template.data {
+            ImageData::ExternalHandle(..) => {
+                // external handle doesn't need to update the texture_cache.
+            }
+            ImageData::Raw(..) | ImageData::ExternalBuffer(..) | ImageData::Blob(..) => {
+                match self.cached_images.entry(request.clone(), self.current_frame_id) {
+                    Occupied(entry) => {
+                        let image_id = entry.get().texture_cache_id;
+
+                        if entry.get().epoch != image_template.epoch {
+                            self.texture_cache.update(image_id,
                                                       image_template.descriptor,
-                                                      filter,
                                                       image_data);
 
-                            entry.insert(CachedImageInfo {
+                            // Update the cached epoch
+                            *entry.into_mut() = CachedImageInfo {
                                 texture_cache_id: image_id,
                                 epoch: image_template.epoch,
-                            });
+                            };
                         }
                     }
+                    Vacant(entry) => {
+                        let image_id = self.texture_cache.new_item_id();
+
+                        let filter = match request.rendering {
+                            ImageRendering::Pixelated => TextureFilter::Nearest,
+                            ImageRendering::Auto | ImageRendering::CrispEdges => TextureFilter::Linear,
+                        };
+
+                        self.texture_cache.insert(image_id,
+                                                  image_template.descriptor,
+                                                  filter,
+                                                  image_data);
+
+                        entry.insert(CachedImageInfo {
+                            texture_cache_id: image_id,
+                            epoch: image_template.epoch,
+                        });
+                    }
                 }
             }
         }
     }
 
     pub fn end_frame(&mut self) {
         debug_assert!(self.state == State::QueryResources);
         self.state = State::Idle;
deleted file mode 100644
--- a/gfx/webrender/src/scroll_tree.rs
+++ /dev/null
@@ -1,394 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-use fnv::FnvHasher;
-use layer::{Layer, ScrollingState};
-use std::collections::{HashMap, HashSet};
-use std::hash::BuildHasherDefault;
-use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform, PipelineId};
-use webrender_traits::{ScrollEventPhase, ScrollLayerId, ScrollLayerInfo, ScrollLayerPixel};
-use webrender_traits::{ScrollLayerRect, ScrollLayerState, ScrollLocation, ScrollToWorldTransform};
-use webrender_traits::{ServoScrollRootId, WorldPoint, as_scroll_parent_rect};
-
-pub type ScrollStates = HashMap<ScrollLayerId, ScrollingState, BuildHasherDefault<FnvHasher>>;
-
-pub struct ScrollTree {
-    pub layers: HashMap<ScrollLayerId, Layer, BuildHasherDefault<FnvHasher>>,
-    pub pending_scroll_offsets: HashMap<(PipelineId, ServoScrollRootId), LayerPoint>,
-
-    /// The ScrollLayerId of the currently scrolling layer. Used to allow the same
-    /// layer to scroll even if a touch operation leaves the boundaries of that layer.
-    pub current_scroll_layer_id: Option<ScrollLayerId>,
-
-    /// The current reference frame id, used for giving a unique id to all new
-    /// reference frames. The ScrollTree increments this by one every time a
-    /// reference frame is created.
-    current_reference_frame_id: usize,
-
-    /// The root reference frame, which is the true root of the ScrollTree. Initially
-    /// this ID is not valid, which is indicated by ```layers``` being empty.
-    pub root_reference_frame_id: ScrollLayerId,
-
-    /// The root scroll layer, which is the first child of the root reference frame.
-    /// Initially this ID is not valid, which is indicated by ```layers``` being empty.
-    pub topmost_scroll_layer_id: ScrollLayerId,
-
-    /// A set of pipelines which should be discarded the next time this
-    /// tree is drained.
-    pub pipelines_to_discard: HashSet<PipelineId>,
-}
-
-impl ScrollTree {
-    pub fn new() -> ScrollTree {
-        let dummy_pipeline = PipelineId(0, 0);
-        ScrollTree {
-            layers: HashMap::with_hasher(Default::default()),
-            pending_scroll_offsets: HashMap::new(),
-            current_scroll_layer_id: None,
-            root_reference_frame_id: ScrollLayerId::root_reference_frame(dummy_pipeline),
-            topmost_scroll_layer_id: ScrollLayerId::root_scroll_layer(dummy_pipeline),
-            current_reference_frame_id: 1,
-            pipelines_to_discard: HashSet::new(),
-        }
-    }
-
-    pub fn root_reference_frame_id(&self) -> ScrollLayerId {
-        // TODO(mrobinson): We should eventually make this impossible to misuse.
-        debug_assert!(!self.layers.is_empty());
-        debug_assert!(self.layers.contains_key(&self.root_reference_frame_id));
-        self.root_reference_frame_id
-    }
-
-    pub fn topmost_scroll_layer_id(&self) -> ScrollLayerId {
-        // TODO(mrobinson): We should eventually make this impossible to misuse.
-        debug_assert!(!self.layers.is_empty());
-        debug_assert!(self.layers.contains_key(&self.topmost_scroll_layer_id));
-        self.topmost_scroll_layer_id
-    }
-
-    pub fn establish_root(&mut self,
-                          pipeline_id: PipelineId,
-                          viewport_size: &LayerSize,
-                          content_size: &LayerSize) {
-        debug_assert!(self.layers.is_empty());
-
-        let identity = LayerToScrollTransform::identity();
-        let viewport = LayerRect::new(LayerPoint::zero(), *viewport_size);
-
-        let root_reference_frame_id = ScrollLayerId::root_reference_frame(pipeline_id);
-        self.root_reference_frame_id = root_reference_frame_id;
-        let reference_frame = Layer::new(&viewport, viewport.size, &identity, pipeline_id);
-        self.layers.insert(self.root_reference_frame_id, reference_frame);
-
-        let scroll_layer = Layer::new(&viewport, *content_size, &identity, pipeline_id);
-        let topmost_scroll_layer_id = ScrollLayerId::root_scroll_layer(pipeline_id);
-        self.topmost_scroll_layer_id = topmost_scroll_layer_id;
-        self.add_layer(scroll_layer, topmost_scroll_layer_id, root_reference_frame_id);
-    }
-
-    pub fn collect_layers_bouncing_back(&self)
-                                        -> HashSet<ScrollLayerId, BuildHasherDefault<FnvHasher>> {
-        let mut layers_bouncing_back = HashSet::with_hasher(Default::default());
-        for (scroll_layer_id, layer) in self.layers.iter() {
-            if layer.scrolling.bouncing_back {
-                layers_bouncing_back.insert(*scroll_layer_id);
-            }
-        }
-        layers_bouncing_back
-    }
-
-    fn find_scrolling_layer_at_point_in_layer(&self,
-                                              cursor: &WorldPoint,
-                                              scroll_layer_id: ScrollLayerId)
-                                              -> Option<ScrollLayerId> {
-        self.layers.get(&scroll_layer_id).and_then(|layer| {
-            for child_layer_id in layer.children.iter().rev() {
-            if let Some(layer_id) =
-                self.find_scrolling_layer_at_point_in_layer(cursor, *child_layer_id) {
-                    return Some(layer_id);
-                }
-            }
-
-            if let ScrollLayerInfo::ReferenceFrame(_) = scroll_layer_id.info {
-                return None;
-            }
-
-            if layer.ray_intersects_layer(cursor) {
-                Some(scroll_layer_id)
-            } else {
-                None
-            }
-        })
-    }
-
-    pub fn find_scrolling_layer_at_point(&self, cursor: &WorldPoint) -> ScrollLayerId {
-        self.find_scrolling_layer_at_point_in_layer(cursor, self.root_reference_frame_id())
-            .unwrap_or(self.topmost_scroll_layer_id())
-    }
-
-    pub fn get_scroll_layer_state(&self) -> Vec<ScrollLayerState> {
-        let mut result = vec![];
-        for (scroll_layer_id, scroll_layer) in self.layers.iter() {
-            match scroll_layer_id.info {
-                ScrollLayerInfo::Scrollable(_, servo_scroll_root_id) => {
-                    result.push(ScrollLayerState {
-                        pipeline_id: scroll_layer.pipeline_id,
-                        scroll_root_id: servo_scroll_root_id,
-                        scroll_offset: scroll_layer.scrolling.offset,
-                    })
-                }
-                ScrollLayerInfo::ReferenceFrame(..) => {}
-            }
-        }
-        result
-    }
-
-    pub fn drain(&mut self) -> ScrollStates {
-        self.current_reference_frame_id = 1;
-
-        let mut scroll_states = HashMap::with_hasher(Default::default());
-        for (layer_id, old_layer) in &mut self.layers.drain() {
-            if !self.pipelines_to_discard.contains(&layer_id.pipeline_id) {
-                scroll_states.insert(layer_id, old_layer.scrolling);
-            }
-        }
-
-        self.pipelines_to_discard.clear();
-        scroll_states
-    }
-
-    pub fn scroll_layers(&mut self,
-                         origin: LayerPoint,
-                         pipeline_id: PipelineId,
-                         scroll_root_id: ServoScrollRootId)
-                         -> bool {
-        if self.layers.is_empty() {
-            self.pending_scroll_offsets.insert((pipeline_id, scroll_root_id), origin);
-            return false;
-        }
-
-        let origin = LayerPoint::new(origin.x.max(0.0), origin.y.max(0.0));
-
-        let mut scrolled_a_layer = false;
-        let mut found_layer = false;
-        for (layer_id, layer) in self.layers.iter_mut() {
-            if layer_id.pipeline_id != pipeline_id {
-                continue;
-            }
-
-            match layer_id.info {
-                ScrollLayerInfo::Scrollable(_, id) if id != scroll_root_id => continue,
-                ScrollLayerInfo::ReferenceFrame(..) => continue,
-                ScrollLayerInfo::Scrollable(..) => {}
-            }
-
-            found_layer = true;
-            scrolled_a_layer |= layer.set_scroll_origin(&origin);
-        }
-
-        if !found_layer {
-            self.pending_scroll_offsets.insert((pipeline_id, scroll_root_id), origin);
-        }
-
-        scrolled_a_layer
-    }
-
-    pub fn scroll(&mut self,
-                  scroll_location: ScrollLocation,
-                  cursor: WorldPoint,
-                  phase: ScrollEventPhase)
-                  -> bool {
-        if self.layers.is_empty() {
-            return false;
-        }
-
-        let scroll_layer_id = match (
-            phase,
-            self.find_scrolling_layer_at_point(&cursor),
-            self.current_scroll_layer_id) {
-            (ScrollEventPhase::Start, scroll_layer_at_point_id, _) => {
-                self.current_scroll_layer_id = Some(scroll_layer_at_point_id);
-                scroll_layer_at_point_id
-            },
-            (_, scroll_layer_at_point_id, Some(cached_scroll_layer_id)) => {
-                let scroll_layer_id = match self.layers.get(&cached_scroll_layer_id) {
-                    Some(_) => cached_scroll_layer_id,
-                    None => {
-                        self.current_scroll_layer_id = Some(scroll_layer_at_point_id);
-                        scroll_layer_at_point_id
-                    },
-                };
-                scroll_layer_id
-            },
-            (_, _, None) => return false,
-        };
-
-        let topmost_scroll_layer_id = self.topmost_scroll_layer_id();
-        let non_root_overscroll = if scroll_layer_id != topmost_scroll_layer_id {
-            // true if the current layer is overscrolling,
-            // and it is not the root scroll layer.
-            let child_layer = self.layers.get(&scroll_layer_id).unwrap();
-            let overscroll_amount = child_layer.overscroll_amount();
-            overscroll_amount.width != 0.0 || overscroll_amount.height != 0.0
-        } else {
-            false
-        };
-
-        let switch_layer = match phase {
-            ScrollEventPhase::Start => {
-                // if this is a new gesture, we do not switch layer,
-                // however we do save the state of non_root_overscroll,
-                // for use in the subsequent Move phase.
-                let mut current_layer = self.layers.get_mut(&scroll_layer_id).unwrap();
-                current_layer.scrolling.should_handoff_scroll = non_root_overscroll;
-                false
-            },
-            ScrollEventPhase::Move(_) => {
-                // Switch layer if movement originated in a new gesture,
-                // from a non root layer in overscroll.
-                let current_layer = self.layers.get_mut(&scroll_layer_id).unwrap();
-                current_layer.scrolling.should_handoff_scroll && non_root_overscroll
-            },
-            ScrollEventPhase::End => {
-                // clean-up when gesture ends.
-                let mut current_layer = self.layers.get_mut(&scroll_layer_id).unwrap();
-                current_layer.scrolling.should_handoff_scroll = false;
-                false
-            },
-        };
-
-        let scroll_layer_info = if switch_layer {
-            topmost_scroll_layer_id.info
-        } else {
-            scroll_layer_id.info
-        };
-
-        let scroll_root_id = match scroll_layer_info {
-             ScrollLayerInfo::Scrollable(_, scroll_root_id) => scroll_root_id,
-             _ => unreachable!("Tried to scroll a reference frame."),
-
-        };
-
-        let mut scrolled_a_layer = false;
-        for (layer_id, layer) in self.layers.iter_mut() {
-            if layer_id.pipeline_id != scroll_layer_id.pipeline_id {
-                continue;
-            }
-
-            match layer_id.info {
-                ScrollLayerInfo::Scrollable(_, id) if id != scroll_root_id => continue,
-                ScrollLayerInfo::ReferenceFrame(..) => continue,
-                _ => {}
-            }
-
-            let scrolled_this_layer = layer.scroll(scroll_location, phase);
-            scrolled_a_layer = scrolled_a_layer || scrolled_this_layer;
-        }
-        scrolled_a_layer
-    }
-
-    pub fn update_all_layer_transforms(&mut self) {
-        if self.layers.is_empty() {
-            return;
-        }
-
-        let root_reference_frame_id = self.root_reference_frame_id();
-        let root_viewport = self.layers[&root_reference_frame_id].local_viewport_rect;
-        self.update_layer_transform(root_reference_frame_id,
-                                    &ScrollToWorldTransform::identity(),
-                                    &as_scroll_parent_rect(&root_viewport));
-    }
-
-    fn update_layer_transform(&mut self,
-                              layer_id: ScrollLayerId,
-                              parent_world_transform: &ScrollToWorldTransform,
-                              parent_viewport_rect: &ScrollLayerRect) {
-        // TODO(gw): This is an ugly borrow check workaround to clone these.
-        //           Restructure this to avoid the clones!
-        let (layer_transform_for_children, viewport_rect, layer_children) = {
-            match self.layers.get_mut(&layer_id) {
-                Some(layer) => {
-                    layer.update_transform(parent_world_transform, parent_viewport_rect);
-
-                    (layer.world_content_transform.with_source::<ScrollLayerPixel>(),
-                     as_scroll_parent_rect(&layer.combined_local_viewport_rect),
-                     layer.children.clone())
-                }
-                None => return,
-            }
-        };
-
-        for child_layer_id in layer_children {
-            self.update_layer_transform(child_layer_id,
-                                        &layer_transform_for_children,
-                                        &viewport_rect);
-        }
-    }
-
-    pub fn tick_scrolling_bounce_animations(&mut self) {
-        for (_, layer) in &mut self.layers {
-            layer.tick_scrolling_bounce_animation()
-        }
-    }
-
-    pub fn finalize_and_apply_pending_scroll_offsets(&mut self, old_states: ScrollStates) {
-        // TODO(gw): These are all independent - can be run through thread pool if it shows up
-        // in the profile!
-        for (scroll_layer_id, layer) in &mut self.layers {
-            let scrolling_state = match old_states.get(&scroll_layer_id) {
-                Some(old_scrolling_state) => *old_scrolling_state,
-                None => ScrollingState::new(),
-            };
-
-            layer.finalize(&scrolling_state);
-
-            let scroll_root_id = match scroll_layer_id.info {
-                ScrollLayerInfo::Scrollable(_, scroll_root_id) => scroll_root_id,
-                _ => continue,
-            };
-
-
-            let pipeline_id = scroll_layer_id.pipeline_id;
-            if let Some(pending_offset) =
-                self.pending_scroll_offsets.remove(&(pipeline_id, scroll_root_id)) {
-                layer.set_scroll_origin(&pending_offset);
-            }
-        }
-
-    }
-
-    pub fn add_reference_frame(&mut self,
-                               rect: LayerRect,
-                               transform: LayerToScrollTransform,
-                               pipeline_id: PipelineId,
-                               parent_id: ScrollLayerId) -> ScrollLayerId {
-        let reference_frame_id = ScrollLayerId {
-            pipeline_id: pipeline_id,
-            info: ScrollLayerInfo::ReferenceFrame(self.current_reference_frame_id),
-        };
-        self.current_reference_frame_id += 1;
-
-        let layer = Layer::new(&rect, rect.size, &transform, pipeline_id);
-        self.add_layer(layer, reference_frame_id, parent_id);
-        reference_frame_id
-    }
-
-    pub fn add_layer(&mut self, layer: Layer, id: ScrollLayerId, parent_id: ScrollLayerId) {
-        debug_assert!(!self.layers.contains_key(&id));
-        self.layers.insert(id, layer);
-
-        debug_assert!(parent_id != id);
-        self.layers.get_mut(&parent_id).unwrap().add_child(id);
-    }
-
-    pub fn discard_frame_state_for_pipeline(&mut self, pipeline_id: PipelineId) {
-        self.pipelines_to_discard.insert(pipeline_id);
-
-        match self.current_scroll_layer_id {
-            Some(id) if id.pipeline_id == pipeline_id => self.current_scroll_layer_id = None,
-            _ => {}
-        }
-    }
-}
-
--- a/gfx/webrender/src/texture_cache.rs
+++ b/gfx/webrender/src/texture_cache.rs
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use device::{MAX_TEXTURE_SIZE, TextureFilter};
+use device::TextureFilter;
 use fnv::FnvHasher;
 use freelist::{FreeList, FreeListItem, FreeListItemId};
 use internal_types::{TextureUpdate, TextureUpdateOp};
 use internal_types::{CacheTextureId, RenderTargetMode, TextureUpdateList, RectUv};
 use std::cmp::{self, Ordering};
 use std::collections::HashMap;
 use std::collections::hash_map::Entry;
 use std::hash::BuildHasherDefault;
@@ -23,19 +23,16 @@ use webrender_traits::ImageDescriptor;
 const MAX_BYTES_PER_TEXTURE: u32 = 1024 * 1024 * 256;  // 256MB
 
 /// The number of RGBA pixels we're allowed to use for a texture.
 const MAX_RGBA_PIXELS_PER_TEXTURE: u32 = MAX_BYTES_PER_TEXTURE / 4;
 
 /// The desired initial size of each texture, in pixels.
 const INITIAL_TEXTURE_SIZE: u32 = 1024;
 
-/// The desired initial area of each texture, in pixels squared.
-const INITIAL_TEXTURE_AREA: u32 = INITIAL_TEXTURE_SIZE * INITIAL_TEXTURE_SIZE;
-
 /// The square root of the number of RGBA pixels we're allowed to use for a texture, rounded down.
 /// to the next power of two.
 const SQRT_MAX_RGBA_PIXELS_PER_TEXTURE: u32 = 8192;
 
 /// The minimum number of pixels on each side that we require for rects to be classified as
 /// "medium" within the free list.
 const MINIMUM_MEDIUM_RECT_SIZE: u32 = 16;
 
@@ -325,19 +322,18 @@ impl TexturePage {
             if rect.size.width > 0 && rect.size.height > 0 {
                 self.free_list.push(rect);
             }
         }
 
         self.texture_size = new_texture_size
     }
 
-    fn can_grow(&self) -> bool {
-        self.texture_size.width < max_texture_size() ||
-        self.texture_size.height < max_texture_size()
+    fn can_grow(&self, max_size: u32) -> bool {
+        self.texture_size.width < max_size || self.texture_size.height < max_size
     }
 }
 
 /// A binning free list. Binning is important to avoid sifting through lots of small strips when
 /// allocating many texture items.
 struct FreeRectList {
     small: Vec<DeviceUintRect>,
     medium: Vec<DeviceUintRect>,
@@ -536,41 +532,51 @@ impl CacheTextureIdList {
 }
 
 pub struct TextureCache {
     cache_id_list: CacheTextureIdList,
     free_texture_levels: HashMap<ImageFormat, Vec<FreeTextureLevel>, BuildHasherDefault<FnvHasher>>,
     items: FreeList<TextureCacheItem>,
     arena: TextureCacheArena,
     pending_updates: TextureUpdateList,
+    max_texture_size: u32,
 }
 
 #[derive(PartialEq, Eq, Debug)]
 pub enum AllocationKind {
     TexturePage,
     Standalone,
 }
 
 #[derive(Debug)]
 pub struct AllocationResult {
     kind: AllocationKind,
     item: TextureCacheItem,
 }
 
 impl TextureCache {
-    pub fn new() -> TextureCache {
+    pub fn new(mut max_texture_size: u32) -> TextureCache {
+        if max_texture_size * max_texture_size > MAX_RGBA_PIXELS_PER_TEXTURE {
+            max_texture_size = SQRT_MAX_RGBA_PIXELS_PER_TEXTURE;
+        }
+
         TextureCache {
             cache_id_list: CacheTextureIdList::new(),
             free_texture_levels: HashMap::with_hasher(Default::default()),
             items: FreeList::new(),
             pending_updates: TextureUpdateList::new(),
             arena: TextureCacheArena::new(),
+            max_texture_size: max_texture_size,
         }
     }
 
+    pub fn max_texture_size(&self) -> u32 {
+        self.max_texture_size
+    }
+
     pub fn pending_updates(&mut self) -> TextureUpdateList {
         mem::replace(&mut self.pending_updates, TextureUpdateList::new())
     }
 
     // TODO(gw): This API is a bit ugly (having to allocate an ID and
     //           then use it). But it has to be that way for now due to
     //           how the raster_jobs code works.
     pub fn new_item_id(&mut self) -> TextureCacheItemId {
@@ -621,18 +627,18 @@ impl TextureCache {
         let page_list = match format {
             ImageFormat::A8 => &mut self.arena.pages_a8,
             ImageFormat::RGBA8 => &mut self.arena.pages_rgba8,
             ImageFormat::RGB8 => &mut self.arena.pages_rgb8,
             ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(),
         };
 
         // TODO(gw): Handle this sensibly (support failing to render items that can't fit?)
-        assert!(requested_size.width < max_texture_size());
-        assert!(requested_size.height < max_texture_size());
+        assert!(requested_size.width < self.max_texture_size);
+        assert!(requested_size.height < self.max_texture_size);
 
         // Loop until an allocation succeeds, growing or adding new
         // texture pages as required.
         loop {
             let location = page_list.last_mut().and_then(|last_page| {
                 last_page.allocate(&requested_size)
             });
 
@@ -646,21 +652,21 @@ impl TextureCache {
                 *self.items.get_mut(image_id) = cache_item;
 
                 return AllocationResult {
                     item: self.items.get(image_id).clone(),
                     kind: AllocationKind::TexturePage,
                 }
             }
 
-            if !page_list.is_empty() && page_list.last().unwrap().can_grow() {
+            if !page_list.is_empty() && page_list.last().unwrap().can_grow(self.max_texture_size) {
                 let last_page = page_list.last_mut().unwrap();
                 // Grow the texture.
-                let new_width = cmp::min(last_page.texture_size.width * 2, max_texture_size());
-                let new_height = cmp::min(last_page.texture_size.height * 2, max_texture_size());
+                let new_width = cmp::min(last_page.texture_size.width * 2, self.max_texture_size);
+                let new_height = cmp::min(last_page.texture_size.height * 2, self.max_texture_size);
                 let texture_size = DeviceUintSize::new(new_width, new_height);
                 self.pending_updates.push(TextureUpdate {
                     id: last_page.texture_id,
                     op: texture_grow_op(texture_size, format, mode),
                 });
                 last_page.grow(texture_size);
 
                 self.items.for_each_item(|item| {
@@ -668,17 +674,17 @@ impl TextureCache {
                         item.texture_size = texture_size;
                     }
                 });
 
                 continue;
             }
 
             // We need a new page.
-            let texture_size = initial_texture_size();
+            let texture_size = initial_texture_size(self.max_texture_size);
             let free_texture_levels_entry = self.free_texture_levels.entry(format);
             let mut free_texture_levels = match free_texture_levels_entry {
                 Entry::Vacant(entry) => entry.insert(Vec::new()),
                 Entry::Occupied(entry) => entry.into_mut(),
             };
             if free_texture_levels.is_empty() {
                 let texture_id = self.cache_id_list.allocate();
 
@@ -709,16 +715,19 @@ impl TextureCache {
         // TODO(gw): Handle updates to size/format!
         debug_assert_eq!(existing_item.allocated_rect.size.width, descriptor.width);
         debug_assert_eq!(existing_item.allocated_rect.size.height, descriptor.height);
 
         let op = match data {
             ImageData::ExternalHandle(..) | ImageData::ExternalBuffer(..)=> {
                 panic!("Doesn't support Update() for external image.");
             }
+            ImageData::Blob(..) => {
+                panic!("The vector image should have been rasterized into a raw image.");
+            }
             ImageData::Raw(bytes) => {
                 TextureUpdateOp::Update {
                     page_pos_x: existing_item.allocated_rect.origin.x,
                     page_pos_y: existing_item.allocated_rect.origin.y,
                     width: descriptor.width,
                     height: descriptor.height,
                     data: bytes,
                     stride: descriptor.stride,
@@ -734,16 +743,20 @@ impl TextureCache {
         self.pending_updates.push(update_op);
     }
 
     pub fn insert(&mut self,
                   image_id: TextureCacheItemId,
                   descriptor: ImageDescriptor,
                   filter: TextureFilter,
                   data: ImageData) {
+        if let ImageData::Blob(..) = data {
+            panic!("must rasterize the vector image before adding to the cache");
+        }
+
         let width = descriptor.width;
         let height = descriptor.height;
         let format = descriptor.format;
         let stride = descriptor.stride;
 
         let result = self.allocate(image_id,
                                    width,
                                    height,
@@ -751,16 +764,19 @@ impl TextureCache {
                                    filter);
 
         match result.kind {
             AllocationKind::TexturePage => {
                 match data {
                     ImageData::ExternalHandle(..) => {
                         panic!("External handle should not go through texture_cache.");
                     }
+                    ImageData::Blob(..) => {
+                        panic!("The vector image should have been rasterized.");
+                    }
                     ImageData::Raw(bytes) => {
                         let update_op = TextureUpdate {
                             id: result.item.texture_id,
                             op: TextureUpdateOp::Update {
                                 page_pos_x: result.item.allocated_rect.origin.x,
                                 page_pos_y: result.item.allocated_rect.origin.y,
                                 width: result.item.allocated_rect.size.width,
                                 height: result.item.allocated_rect.size.height,
@@ -872,27 +888,12 @@ impl FitsInside for DeviceUintSize {
 
 /// FIXME(pcwalton): Would probably be more efficient as a bit vector.
 #[derive(Clone, Copy)]
 pub struct FreeTextureLevel {
     texture_id: CacheTextureId,
 }
 
 /// Returns the number of pixels on a side we start out with for our texture atlases.
-fn initial_texture_size() -> DeviceUintSize {
-    let max_hardware_texture_size = *MAX_TEXTURE_SIZE as u32;
-    let initial_size = if max_hardware_texture_size * max_hardware_texture_size > INITIAL_TEXTURE_AREA {
-        INITIAL_TEXTURE_SIZE
-    } else {
-        max_hardware_texture_size
-    };
+fn initial_texture_size(max_texture_size: u32) -> DeviceUintSize {
+    let initial_size = cmp::min(max_texture_size, INITIAL_TEXTURE_SIZE);
     DeviceUintSize::new(initial_size, initial_size)
 }
-
-/// Returns the number of pixels on a side we're allowed to use for our texture atlases.
-fn max_texture_size() -> u32 {
-    let max_hardware_texture_size = *MAX_TEXTURE_SIZE as u32;
-    if max_hardware_texture_size * max_hardware_texture_size > MAX_RGBA_PIXELS_PER_TEXTURE {
-        SQRT_MAX_RGBA_PIXELS_PER_TEXTURE
-    } else {
-        max_hardware_texture_size
-    }
-}
--- a/gfx/webrender/src/tiling.rs
+++ b/gfx/webrender/src/tiling.rs
@@ -529,30 +529,31 @@ impl AlphaBatcher {
 
         for task in &mut self.tasks {
             let task_index = render_tasks.get_static_task_index(&task.task_id);
             let mut existing_opaque_batch_index = 0;
 
             for item in &task.alpha_items {
                 let (batch_key, item_bounding_rect) = match item {
                     &AlphaRenderItem::Blend(stacking_context_index, ..) => {
-                        let stacking_context = &ctx.stacking_context_store[stacking_context_index.0];
+                        let stacking_context =
+                            &ctx.stacking_context_store[stacking_context_index.0];
                         (AlphaBatchKey::new(AlphaBatchKind::Blend,
                                             AlphaBatchKeyFlags::empty(),
                                             BlendMode::Alpha,
                                             BatchTextures::no_texture()),
-                         &stacking_context.xf_rect.as_ref().unwrap().bounding_rect)
+                         &stacking_context.bounding_rect)
                     }
                     &AlphaRenderItem::HardwareComposite(stacking_context_index, _, composite_op, ..) => {
                         let stacking_context = &ctx.stacking_context_store[stacking_context_index.0];
                         (AlphaBatchKey::new(AlphaBatchKind::HardwareComposite,
                                             AlphaBatchKeyFlags::empty(),
                                             composite_op.to_blend_mode(),
                                             BatchTextures::no_texture()),
-                         &stacking_context.xf_rect.as_ref().unwrap().bounding_rect)
+                         &stacking_context.bounding_rect)
                     }
                     &AlphaRenderItem::Composite(stacking_context_index,
                                                 backdrop_id,
                                                 src_id,
                                                 info,
                                                 z) => {
                         // Composites always get added to their own batch.
                         // This is because the result of a composite can affect
@@ -562,21 +563,20 @@ impl AlphaBatcher {
                                                                   task_index,
                                                                   render_tasks.get_task_index(&backdrop_id, child_pass_index),
                                                                   render_tasks.get_static_task_index(&src_id),
                                                                   info,
                                                                   z);
                         alpha_batches.push(batch);
                         continue;
                     }
-                    &AlphaRenderItem::Primitive(stacking_context_index, prim_index, _) => {
-                        let stacking_context =
-                            &ctx.stacking_context_store[stacking_context_index.0];
+                    &AlphaRenderItem::Primitive(clip_scroll_group_index, prim_index, _) => {
+                        let group = &ctx.clip_scroll_group_store[clip_scroll_group_index.0];
                         let prim_metadata = ctx.prim_store.get_metadata(prim_index);
-                        let transform_kind = stacking_context.xf_rect.as_ref().unwrap().kind;
+                        let transform_kind = group.xf_rect.as_ref().unwrap().kind;
                         let needs_clipping = prim_metadata.clip_task.is_some();
                         let needs_blending = transform_kind == TransformedRectKind::Complex ||
                                              !prim_metadata.is_opaque ||
                                              needs_clipping;
                         let blend_mode = ctx.prim_store.get_blend_mode(needs_blending, prim_metadata);
                         let needs_clipping_flag = if needs_clipping {
                             NEEDS_CLIPPING
                         } else {
@@ -611,21 +611,17 @@ impl AlphaBatcher {
                     }
 
                     // check for intersections
                     for item in &batch.items {
                         let intersects = match *item {
                             PrimitiveBatchItem::StackingContext(stacking_context_index) => {
                                 let stacking_context =
                                     &ctx.stacking_context_store[stacking_context_index.0];
-                                stacking_context.xf_rect
-                                                .as_ref()
-                                                .unwrap()
-                                                .bounding_rect
-                                                .intersects(item_bounding_rect)
+                                stacking_context.bounding_rect.intersects(item_bounding_rect)
                             }
                             PrimitiveBatchItem::Primitive(prim_index) => {
                                 let bounding_rect = &ctx.prim_store.cpu_bounding_rects[prim_index.0];
                                 bounding_rect.as_ref().unwrap().intersects(item_bounding_rect)
                             }
                         };
 
                         if intersects {
@@ -660,45 +656,46 @@ impl AlphaBatcher {
                         ctx.prim_store.add_blend_to_batch(stacking_context_index,
                                                           batch,
                                                           task_index,
                                                           render_tasks.get_static_task_index(&src_id),
                                                           info,
                                                           z);
                     }
                     &AlphaRenderItem::HardwareComposite(stacking_context_index, src_id, _, z) => {
-                        ctx.prim_store.add_hardware_composite_to_batch(stacking_context_index,
-                                                                       batch,
-                                                                       task_index,
-                                                                       render_tasks.get_static_task_index(&src_id),
-                                                                       z);
+                        ctx.prim_store.add_hardware_composite_to_batch(
+                            stacking_context_index,
+                            batch,
+                            task_index,
+                            render_tasks.get_static_task_index(&src_id),
+                            z);
                     }
-                    &AlphaRenderItem::Primitive(stacking_context_index, prim_index, z) => {
-                        let stacking_context =
-                            &ctx.stacking_context_store[stacking_context_index.0];
+                    &AlphaRenderItem::Primitive(clip_scroll_group_index, prim_index, z) => {
+                        let packed_layer = ctx.clip_scroll_group_store[clip_scroll_group_index.0]
+                                              .packed_layer_index;
                         ctx.prim_store.add_prim_to_batch(prim_index,
                                                          batch,
-                                                         stacking_context.packed_layer_index,
+                                                         packed_layer,
                                                          task_index,
                                                          render_tasks,
                                                          child_pass_index,
                                                          z);
                     }
                 }
             }
 
             for item in task.opaque_items.iter().rev() {
                 let batch_key = match item {
                     &AlphaRenderItem::Composite(..) => unreachable!(),
                     &AlphaRenderItem::Blend(..) => unreachable!(),
                     &AlphaRenderItem::HardwareComposite(..) => unreachable!(),
-                    &AlphaRenderItem::Primitive(stacking_context_index, prim_index, _) => {
-                        let stacking_context = &ctx.stacking_context_store[stacking_context_index.0];
+                    &AlphaRenderItem::Primitive(clip_scroll_group_index, prim_index, _) => {
+                        let group = &ctx.clip_scroll_group_store[clip_scroll_group_index.0];
+                        let transform_kind = group.xf_rect.as_ref().unwrap().kind;
                         let prim_metadata = ctx.prim_store.get_metadata(prim_index);
-                        let transform_kind = stacking_context.xf_rect.as_ref().unwrap().kind;
                         let needs_clipping = prim_metadata.clip_task.is_some();
                         let needs_blending = transform_kind == TransformedRectKind::Complex ||
                                              !prim_metadata.is_opaque ||
                                              needs_clipping;
                         let blend_mode = ctx.prim_store.get_blend_mode(needs_blending, prim_metadata);
                         let needs_clipping_flag = if needs_clipping {
                             NEEDS_CLIPPING
                         } else {
@@ -740,22 +737,23 @@ impl AlphaBatcher {
                     opaque_batches.push(new_batch)
                 }
 
                 let batch = &mut opaque_batches[existing_opaque_batch_index];
                 match item {
                     &AlphaRenderItem::Composite(..) => unreachable!(),
                     &AlphaRenderItem::Blend(..) => unreachable!(),
                     &AlphaRenderItem::HardwareComposite(..) => unreachable!(),
-                    &AlphaRenderItem::Primitive(stacking_context_index, prim_index, z) => {
-                        let stacking_context =
-                            &ctx.stacking_context_store[stacking_context_index.0];
+                    &AlphaRenderItem::Primitive(clip_scroll_group_index, prim_index, z) => {
+                        let packed_layer_index =
+                            ctx.clip_scroll_group_store[clip_scroll_group_index.0]
+                               .packed_layer_index;
                         ctx.prim_store.add_prim_to_batch(prim_index,
                                                          batch,
-                                                         stacking_context.packed_layer_index,
+                                                         packed_layer_index,
                                                          task_index,
                                                          render_tasks,
                                                          child_pass_index,
                                                          z);
                     }
                 }
             }
         }
@@ -843,16 +841,17 @@ impl ClipBatcher {
                 })
             }
         }
     }
 }
 
 pub struct RenderTargetContext<'a> {
     pub stacking_context_store: &'a [StackingContext],
+    pub clip_scroll_group_store: &'a [ClipScrollGroup],
     pub prim_store: &'a PrimitiveStore,
     pub resource_cache: &'a ResourceCache,
 }
 
 /// A render target represents a number of rendering operations on a surface.
 pub struct RenderTarget {
     pub alpha_batcher: AlphaBatcher,
     pub clip_batcher: ClipBatcher,
@@ -1294,24 +1293,73 @@ impl PrimitiveBatch {
 }
 
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
 pub struct PackedLayerIndex(pub usize);
 
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
 pub struct StackingContextIndex(pub usize);
 
+#[derive(Debug)]
 pub struct StackingContext {
     pub pipeline_id: PipelineId,
     pub local_transform: LayerToScrollTransform,
     pub local_rect: LayerRect,
+    pub bounding_rect: DeviceIntRect,
+    pub composite_ops: CompositeOps,
+    pub clip_scroll_groups: Vec<ClipScrollGroupIndex>,
+    pub is_visible: bool,
+}
+
+impl StackingContext {
+    pub fn new(pipeline_id: PipelineId,
+               local_transform: LayerToScrollTransform,
+               local_rect: LayerRect,
+               composite_ops: CompositeOps,
+               clip_scroll_group_index: ClipScrollGroupIndex)
+               -> StackingContext {
+        StackingContext {
+            pipeline_id: pipeline_id,
+            local_transform: local_transform,
+            local_rect: local_rect,
+            bounding_rect: DeviceIntRect::zero(),
+            composite_ops: composite_ops,
+            clip_scroll_groups: vec![clip_scroll_group_index],
+            is_visible: false,
+        }
+    }
+
+    pub fn clip_scroll_group(&self) -> ClipScrollGroupIndex {
+        // Currently there is only one scrolled stacking context per context,
+        // but eventually this will be selected from the vector based on the
+        // scroll layer of this primitive.
+        self.clip_scroll_groups[0]
+    }
+
+    pub fn can_contribute_to_scene(&self) -> bool {
+        !self.composite_ops.will_make_invisible()
+    }
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
+pub struct ClipScrollGroupIndex(pub usize);
+
+#[derive(Debug)]
+pub struct ClipScrollGroup {
+    pub stacking_context_index: StackingContextIndex,
     pub scroll_layer_id: ScrollLayerId,
+    pub packed_layer_index: PackedLayerIndex,
+    pub pipeline_id: PipelineId,
     pub xf_rect: Option<TransformedRect>,
-    pub composite_ops: CompositeOps,
-    pub packed_layer_index: PackedLayerIndex,
+}
+
+impl ClipScrollGroup {
+    pub fn is_visible(&self) -> bool {
+        self.xf_rect.is_some()
+    }
 }
 
 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
 pub struct ScrollLayerIndex(pub usize);
 
 pub struct ScrollLayer {
     pub scroll_layer_id: ScrollLayerId,
     pub parent_index: ScrollLayerIndex,
@@ -1381,26 +1429,16 @@ impl CompositeOps {
                 &LowLevelFilterOp::Opacity(Au(0)) => return true,
                 _ => {}
             }
         }
         false
     }
 }
 
-impl StackingContext {
-    pub fn is_visible(&self) -> bool {
-        self.xf_rect.is_some()
-    }
-
-    pub fn can_contribute_to_scene(&self) -> bool {
-        !self.composite_ops.will_make_invisible()
-    }
-}
-
 /// A rendering-oriented representation of frame::Frame built by the render backend
 /// and presented to the renderer.
 pub struct Frame {
     pub viewport_size: LayerSize,
     pub background_color: Option<ColorF>,
     pub device_pixel_ratio: f32,
     pub cache_size: DeviceUintSize,
     pub passes: Vec<RenderPass>,
--- a/gfx/webrender_bindings/Cargo.toml
+++ b/gfx/webrender_bindings/Cargo.toml
@@ -1,24 +1,24 @@
 [package]
 name = "webrender_bindings"
 version = "0.1.0"
 authors = ["The Mozilla Project Developers"]
 license = "MPL-2.0"
 
 [dependencies]
-webrender_traits = {path = "../webrender_traits", version = "0.14"}
-euclid = "0.10"
-app_units = "0.3"
+webrender_traits = {path = "../webrender_traits", version = "0.19"}
+euclid = "0.11"
+app_units = "0.4"
 gleam = "0.2"
 fnv="1.0"
 
 [dependencies.webrender]
 path = "../webrender"
-version = "0.15"
+version = "0.19"
 default-features = false
 features = ["codegen"]
 
 [target.'cfg(target_os = "macos")'.dependencies]
 core-foundation = "0.2.2"
 
 [target.'cfg(target_os = "windows")'.dependencies]
 kernel32-sys = "0.2"
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -13,21 +13,23 @@
 namespace mozilla {
 namespace wr {
 
 class NewRenderer : public RendererEvent
 {
 public:
   NewRenderer(WrAPI** aApi, layers::CompositorBridgeParentBase* aBridge,
               GLint* aMaxTextureSize,
+              bool* aUseANGLE,
               RefPtr<widget::CompositorWidget>&& aWidget,
               layers::SynchronousTask* aTask,
               bool aEnableProfiler)
     : mWrApi(aApi)
     , mMaxTextureSize(aMaxTextureSize)
+    , mUseANGLE(aUseANGLE)
     , mBridge(aBridge)
     , mCompositorWidget(Move(aWidget))
     , mTask(aTask)
     , mEnableProfiler(aEnableProfiler)
   {
     MOZ_COUNT_CTOR(NewRenderer);
   }
 
@@ -41,16 +43,17 @@ public:
     layers::AutoCompleteTask complete(mTask);
 
     RefPtr<gl::GLContext> gl = gl::GLContextProvider::CreateForCompositorWidget(mCompositorWidget, true);
     if (!gl || !gl->MakeCurrent()) {
       return;
     }
 
     gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, mMaxTextureSize);
+    *mUseANGLE = gl->IsANGLE();
 
     WrRenderer* wrRenderer = nullptr;
     if (!wr_window_new(aWindowId, gl.get(), this->mEnableProfiler, nullptr, mWrApi, &wrRenderer)) {
       return;
     }
     MOZ_ASSERT(wrRenderer);
 
     RefPtr<RenderThread> thread = &aRenderThread;
@@ -62,16 +65,17 @@ public:
                                             mBridge);
 
     aRenderThread.AddRenderer(aWindowId, Move(renderer));
   }
 
 private:
   WrAPI** mWrApi;
   GLint* mMaxTextureSize;
+  bool* mUseANGLE;
   layers::CompositorBridgeParentBase* mBridge;
   RefPtr<widget::CompositorWidget> mCompositorWidget;
   layers::SynchronousTask* mTask;
   bool mEnableProfiler;
 };
 
 class RemoveRenderer : public RendererEvent
 {
@@ -107,32 +111,33 @@ WebRenderAPI::Create(bool aEnableProfile
   MOZ_ASSERT(aBridge);
   MOZ_ASSERT(aWidget);
 
   static uint64_t sNextId = 1;
   auto id = NewWindowId(sNextId++);
 
   WrAPI* wrApi = nullptr;
   GLint maxTextureSize = 0;
+  bool useANGLE = false;
 
   // Dispatch a synchronous task because the WrApi object needs to be created
   // on the render thread. If need be we could delay waiting on this task until
   // the next time we need to access the WrApi object.
   layers::SynchronousTask task("Create Renderer");
-  auto event = MakeUnique<NewRenderer>(&wrApi, aBridge, &maxTextureSize,
+  auto event = MakeUnique<NewRenderer>(&wrApi, aBridge, &maxTextureSize, &useANGLE,
                                        Move(aWidget), &task, aEnableProfiler);
   RenderThread::Get()->RunEvent(id, Move(event));
 
   task.Wait();
 
   if (!wrApi) {
     return nullptr;
   }
 
-  return RefPtr<WebRenderAPI>(new WebRenderAPI(wrApi, id, maxTextureSize)).forget();
+  return RefPtr<WebRenderAPI>(new WebRenderAPI(wrApi, id, maxTextureSize, useANGLE)).forget();
 }
 
 WebRenderAPI::~WebRenderAPI()
 {
   layers::SynchronousTask task("Destroy WebRenderAPI");
   auto event = MakeUnique<RemoveRenderer>(&task);
   RunOnRenderThread(Move(event));
   task.Wait();
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -66,29 +66,32 @@ public:
   void DeleteFont(wr::FontKey aKey);
 
   void SetProfilerEnabled(bool aEnabled);
 
   void RunOnRenderThread(UniquePtr<RendererEvent> aEvent);
   void Readback(gfx::IntSize aSize, uint8_t *aBuffer, uint32_t aBufferSize);
 
   GLint GetMaxTextureSize() const { return mMaxTextureSize; }
+  bool GetUseANGLE() const { return mUseANGLE; }
 
 protected:
-  WebRenderAPI(WrAPI* aRawApi, wr::WindowId aId, GLint aMaxTextureSize)
+  WebRenderAPI(WrAPI* aRawApi, wr::WindowId aId, GLint aMaxTextureSize, bool aUseANGLE)
     : mWrApi(aRawApi)
     , mId(aId)
     , mMaxTextureSize(aMaxTextureSize)
+    , mUseANGLE(aUseANGLE)
   {}
 
   ~WebRenderAPI();
 
   WrAPI* mWrApi;
   wr::WindowId mId;
   GLint mMaxTextureSize;
+  bool mUseANGLE;
 
   friend class DisplayListBuilder;
 };
 
 /// This is a simple C++ wrapper around WrState defined in the rust bindings.
 /// We may want to turn this into a direct wrapper on top of WebRenderFrameBuilder
 /// instead, so the interface may change a bit.
 class DisplayListBuilder {
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -222,16 +222,24 @@ static inline WrRect ToWrRect(const gfx:
 }
 
 template<class T>
 static inline WrRect ToWrRect(const gfx::IntRectTyped<T>& rect)
 {
   return ToWrRect(IntRectToRect(rect));
 }
 
+static inline WrPoint ToWrPoint(const gfx::Point& point)
+{
+  WrPoint p;
+  p.x = point.x;
+  p.y = point.y;
+  return p;
+}
+
 struct ByteBuffer
 {
   ByteBuffer(size_t aLength, uint8_t* aData)
     : mLength(aLength)
     , mData(aData)
     , mOwned(false)
   {}
 
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1,14 +1,14 @@
 use std::ffi::CString;
 use std::{mem, slice};
 use std::path::PathBuf;
 use std::os::raw::{c_void, c_char};
 use gleam::gl;
-use webrender_traits::{BorderSide, BorderStyle, BorderRadius};
+use webrender_traits::{BorderSide, BorderStyle, BorderRadius, BorderWidths, BorderDetails, NormalBorder};
 use webrender_traits::{PipelineId, ClipRegion, PropertyBinding};
 use webrender_traits::{Epoch, ExtendMode, ColorF, GlyphInstance, GradientStop, ImageDescriptor};
 use webrender_traits::{FilterOp, ImageData, ImageFormat, ImageKey, ImageMask, ImageRendering, RendererKind, MixBlendMode};
 use webrender_traits::{ExternalImageId, RenderApi, FontKey};
 use webrender_traits::{DeviceUintSize, ExternalEvent};
 use webrender_traits::{LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
 use webrender_traits::{BoxShadowClipMode, LayerPixel, ServoScrollRootId};
 use webrender::renderer::{Renderer, RendererOptions};
@@ -184,30 +184,20 @@ pub extern fn wr_window_new(window_id: W
     gl::load_with(|symbol| get_proc_address(gl_context, symbol));
     gl::clear_color(0.3, 0.0, 0.0, 1.0);
 
     let version = gl::get_string(gl::VERSION);
 
     println!("WebRender - OpenGL version new {}", version);
 
     let opts = RendererOptions {
-        device_pixel_ratio: 1.0,
-        resource_override_path: None,
         enable_aa: false,
-        enable_subpixel_aa: false,
         enable_profiler: enable_profiler,
-        enable_scrollbars: false,
-        precache_shaders: false,
-        renderer_kind: RendererKind::Native,
-        debug: false,
-        clear_framebuffer: true,
-        render_target_debug: false,
-        clear_color: ColorF::new(1.0, 1.0, 1.0, 1.0),
         recorder: recorder,
-        workers: None,
+        .. Default::default()
     };
 
     let (mut renderer, sender) = match Renderer::new(opts) {
         Ok((renderer, sender)) => { (renderer, sender) }
         Err(e) => {
             println!(" Failed to create a Renderer: {:?}", e);
             return false;
         }
@@ -600,26 +590,29 @@ pub extern fn wr_api_set_root_pipeline(a
     api.set_root_pipeline(pipeline_id);
     api.generate_frame(None);
 }
 
 #[no_mangle]
 pub extern fn wr_api_add_image(api: &mut RenderApi, descriptor: &WrImageDescriptor, bytes: * const u8, size: usize) -> ImageKey {
     assert!( unsafe { is_in_compositor_thread() });
     let bytes = unsafe { slice::from_raw_parts(bytes, size).to_owned() };
-    return api.add_image(
+    let image_key = api.generate_image_key();
+    api.add_image(
+        image_key,
         ImageDescriptor {
             width: descriptor.width,
             height: descriptor.height,
             stride: if descriptor.stride != 0 { Some(descriptor.stride) } else { None },
             format: descriptor.format,
             is_opaque: descriptor.is_opaque,
         },
         ImageData::new(bytes)
     );
+    image_key
 }
 
 #[no_mangle]
 pub extern fn wr_api_add_external_image_texture(api: &mut RenderApi, width: u32, height: u32, format: ImageFormat, external_image_id: u64) -> ImageKey {
     assert!( unsafe { is_in_compositor_thread() });
     unimplemented!(); // TODO
     //api.add_image(ImageDescriptor{width:width, height:height, stride:None, format: format, is_opaque: false}, ImageData::External(ExternalImageId(external_image_id)))
 }
@@ -685,24 +678,34 @@ pub extern fn wr_dp_push_box_shadow(stat
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_border(state: &mut WrState, rect: WrRect, clip: WrRect,
                                 top: WrBorderSide, right: WrBorderSide, bottom: WrBorderSide, left: WrBorderSide,
                                 radius: WrBorderRadius) {
     assert!( unsafe { is_in_compositor_thread() });
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
+    let border_widths = BorderWidths {
+        left: left.width,
+        top: top.width,
+        right: right.width,
+        bottom: bottom.width
+    };
+    let border_details = BorderDetails::Normal(NormalBorder {
+        left: left.to_border_side(),
+        right: right.to_border_side(),
+        top: top.to_border_side(),
+        bottom: bottom.to_border_side(),
+        radius: radius.to_border_radius(),
+    });
     state.frame_builder.dl_builder.push_border(
                                     rect.to_rect(),
                                     clip_region,
-                                    left.to_border_side(),
-                                    top.to_border_side(),
-                                    right.to_border_side(),
-                                    bottom.to_border_side(),
-                                    radius.to_border_radius());
+                                    border_widths,
+                                    border_details);
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_linear_gradient(state: &mut WrState, rect: WrRect, clip: WrRect,
                                          start_point: WrPoint, end_point: WrPoint,
                                          stops: * const WrGradientStop, stops_count: usize,
                                          extend_mode: WrGradientExtendMode) {
     assert!( unsafe { is_in_compositor_thread() });
@@ -798,17 +801,17 @@ pub struct WrBorderSide
     color: WrColor,
     style: BorderStyle
 }
 
 impl WrBorderSide
 {
     pub fn to_border_side(&self) -> BorderSide
     {
-        BorderSide { width: self.width, color: self.color.to_color(), style: self.style }
+        BorderSide { color: self.color.to_color(), style: self.style }
     }
 }
 
 #[repr(C)]
 pub struct WrGradientStop
 {
     offset: f32,
     color: WrColor,
@@ -924,17 +927,19 @@ pub extern fn wr_api_add_raw_font(api: &
     assert!( unsafe { is_in_compositor_thread() });
 
     let font_slice = unsafe {
         slice::from_raw_parts(font_buffer, buffer_size as usize)
     };
     let mut font_vector = Vec::new();
     font_vector.extend_from_slice(font_slice);
 
-    return api.add_raw_font(font_vector);
+    let font_key = api.generate_font_key();
+    api.add_raw_font(font_key, font_vector);
+    font_key
 }
 
 #[no_mangle]
 pub extern fn wr_dp_push_text(state: &mut WrState,
                               bounds: WrRect,
                               clip: WrRect,
                               color: WrColor,
                               font_key: FontKey,
--- a/gfx/webrender_bindings/webrender_ffi.h
+++ b/gfx/webrender_bindings/webrender_ffi.h
@@ -278,16 +278,17 @@ struct WrPoint
 {
   float x;
   float y;
 
   bool operator==(const WrPoint& aRhs) const {
     return x == aRhs.x && y == aRhs.y;
   }
 
+  operator mozilla::gfx::Point() const { return mozilla::gfx::Point(x, y); }
 };
 
 struct WrImageMask
 {
   WrImageKey image;
   WrRect rect;
   bool repeat;
 
--- a/gfx/webrender_traits/Cargo.toml
+++ b/gfx/webrender_traits/Cargo.toml
@@ -1,35 +1,35 @@
 [package]
 name = "webrender_traits"
-version = "0.14.0"
+version = "0.19.0"
 authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
 license = "MPL-2.0"
 repository = "https://github.com/servo/webrender"
 build = "build.rs"
 
 [features]
 default = ["codegen"]
 nightly = ["euclid/unstable", "serde/unstable"]
 codegen = ["serde_codegen", "serde_codegen/with-syntex"]
 ipc = ["ipc-channel"]
 
 [dependencies]
-app_units = "0.3.0"
+app_units = "0.4"
 byteorder = "1.0"
-euclid = "0.10.3"
+euclid = "0.11"
 gleam = "0.2"
 heapsize = "0.3.6"
-offscreen_gl_context = {version = "0.5.0", features = ["serde_serialization"]}
-serde = "0.8"
-serde_derive = {version = "0.8", optional = true}
-ipc-channel = { version = "0.5.0", optional = true }
+ipc-channel = {version = "0.7", optional = true}
+offscreen_gl_context = {version = "0.6", features = ["serde"]}
+serde = "0.9"
+serde_derive = {version = "0.9", optional = true}
 
 [target.'cfg(target_os = "macos")'.dependencies]
-core-graphics = "0.6"
+core-graphics = "0.7"
 
 [target.'cfg(target_os = "windows")'.dependencies]
-dwrote = "0.1.1"
+servo-dwrote = "0.2"
 
 [build-dependencies.serde_codegen]
-version = "0.8"
+version = "0.9"
 default_features = false
 optional = true
--- a/gfx/webrender_traits/src/api.rs
+++ b/gfx/webrender_traits/src/api.rs
@@ -49,59 +49,57 @@ pub struct RenderApi {
     pub next_id: Cell<ResourceId>,
 }
 
 impl RenderApi {
     pub fn clone_sender(&self) -> RenderApiSender {
         RenderApiSender::new(self.api_sender.clone(), self.payload_sender.clone())
     }
 
-    pub fn add_raw_font(&self, bytes: Vec<u8>) -> FontKey {
+    pub fn generate_font_key(&self) -> FontKey {
         let new_id = self.next_unique_id();
-        let key = FontKey::new(new_id.0, new_id.1);
+        FontKey::new(new_id.0, new_id.1)
+    }
+
+    pub fn add_raw_font(&self, key: FontKey, bytes: Vec<u8>) {
         let msg = ApiMsg::AddRawFont(key, bytes);
         self.api_sender.send(msg).unwrap();
-        key
     }
 
-    pub fn add_native_font(&self, native_font_handle: NativeFontHandle) -> FontKey {
-        let new_id = self.next_unique_id();
-        let key = FontKey::new(new_id.0, new_id.1);
+    pub fn add_native_font(&self, key: FontKey, native_font_handle: NativeFontHandle) {
         let msg = ApiMsg::AddNativeFont(key, native_font_handle);
         self.api_sender.send(msg).unwrap();
-        key
     }
 
     /// Gets the dimensions for the supplied glyph keys
     ///
     /// Note: Internally, the internal texture cache doesn't store
     /// 'empty' textures (height or width = 0)
     /// This means that glyph dimensions e.g. for spaces (' ') will mostly be None.
     pub fn get_glyph_dimensions(&self, glyph_keys: Vec<GlyphKey>)
                                 -> Vec<Option<GlyphDimensions>> {
         let (tx, rx) = channel::msg_channel().unwrap();
         let msg = ApiMsg::GetGlyphDimensions(glyph_keys, tx);
         self.api_sender.send(msg).unwrap();
         rx.recv().unwrap()
     }
 
     /// Creates an `ImageKey`.
-    pub fn alloc_image(&self) -> ImageKey {
+    pub fn generate_image_key(&self) -> ImageKey {
         let new_id = self.next_unique_id();
         ImageKey::new(new_id.0, new_id.1)
     }
 
-    /// Adds an image and returns the corresponding `ImageKey`.
+    /// Adds an image identified by the `ImageKey`.
     pub fn add_image(&self,
+                     key: ImageKey,
                      descriptor: ImageDescriptor,
-                     data: ImageData) -> ImageKey {
-        let key = self.alloc_image();
+                     data: ImageData) {
         let msg = ApiMsg::AddImage(key, descriptor, data);
         self.api_sender.send(msg).unwrap();
-        key
     }
 
     /// Updates a specific image.
     ///
     /// Currently doesn't support changing dimensions or format by updating.
     // TODO: Support changing dimensions (and format) during image update?
     pub fn update_image(&self,
                         key: ImageKey,
--- a/gfx/webrender_traits/src/channel_mpsc.rs
+++ b/gfx/webrender_traits/src/channel_mpsc.rs
@@ -62,32 +62,32 @@ pub fn msg_channel<T>() -> Result<(MsgSe
 /// recording tool. The recording tool only outputs messages
 /// that don't contain Senders or Receivers, so in theory
 /// these should never be called in the in-process config.
 /// If they are called, there may be a bug in the messages
 /// that the replay tool is writing.
 ///
 
 impl<T> Serialize for MsgReceiver<T> {
-    fn serialize<S: Serializer>(&self, _: &mut S) -> Result<(), S::Error> {
+    fn serialize<S: Serializer>(&self, _: S) -> Result<S::Ok, S::Error> {
         unreachable!();
     }
 }
 
 impl<T> Serialize for MsgSender<T> {
-    fn serialize<S: Serializer>(&self, _: &mut S) -> Result<(), S::Error> {
+    fn serialize<S: Serializer>(&self, _: S) -> Result<S::Ok, S::Error> {
         unreachable!();
     }
 }
 
 impl<T> Deserialize for MsgReceiver<T> {
-    fn deserialize<D>(_: &mut D) -> Result<MsgReceiver<T>, D::Error>
+    fn deserialize<D>(_: D) -> Result<MsgReceiver<T>, D::Error>
                       where D: Deserializer {
         unreachable!();
     }
 }
 
 impl<T> Deserialize for MsgSender<T> {
-    fn deserialize<D>(_: &mut D) -> Result<MsgSender<T>, D::Error>
+    fn deserialize<D>(_: D) -> Result<MsgSender<T>, D::Error>
                       where D: Deserializer {
         unreachable!();
     }
 }
--- a/gfx/webrender_traits/src/display_item.rs
+++ b/gfx/webrender_traits/src/display_item.rs
@@ -1,40 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use display_list::AuxiliaryListsBuilder;
-use {BorderRadius, BorderDisplayItem, ClipRegion, ColorF, ComplexClipRegion};
+use {BorderRadius, ClipRegion, ColorF, ComplexClipRegion};
 use {FontKey, ImageKey, PipelineId, ScrollLayerId, ScrollLayerInfo, ServoScrollRootId};
 use {ImageMask, ItemRange};
 use {LayoutSize, LayoutPoint, LayoutRect};
 
-impl BorderDisplayItem {
-    pub fn top_left_inner_radius(&self) -> LayoutSize {
-        LayoutSize::new((self.radius.top_left.width - self.left.width).max(0.0),
-                     (self.radius.top_left.height - self.top.width).max(0.0))
-    }
-
-    pub fn top_right_inner_radius(&self) -> LayoutSize {
-        LayoutSize::new((self.radius.top_right.width - self.right.width).max(0.0),
-                     (self.radius.top_right.height - self.top.width).max(0.0))
-    }
-
-    pub fn bottom_left_inner_radius(&self) -> LayoutSize {
-        LayoutSize::new((self.radius.bottom_left.width - self.left.width).max(0.0),
-                     (self.radius.bottom_left.height - self.bottom.width).max(0.0))
-    }
-
-    pub fn bottom_right_inner_radius(&self) -> LayoutSize {
-        LayoutSize::new((self.radius.bottom_right.width - self.right.width).max(0.0),
-                     (self.radius.bottom_right.height - self.bottom.width).max(0.0))
-    }
-}
-
 impl BorderRadius {
     pub fn zero() -> BorderRadius {
         BorderRadius {
             top_left: LayoutSize::new(0.0, 0.0),
             top_right: LayoutSize::new(0.0, 0.0),
             bottom_left: LayoutSize::new(0.0, 0.0),
             bottom_right: LayoutSize::new(0.0, 0.0),
         }
@@ -44,30 +22,46 @@ impl BorderRadius {
         BorderRadius {
             top_left: LayoutSize::new(radius, radius),
             top_right: LayoutSize::new(radius, radius),
             bottom_left: LayoutSize::new(radius, radius),
             bottom_right: LayoutSize::new(radius, radius),
         }
     }
 
-    pub fn is_uniform(&self) -> Option<LayoutSize> {
+    pub fn uniform_size(radius: LayoutSize) -> BorderRadius {
+        BorderRadius {
+            top_left: radius,
+            top_right: radius,
+            bottom_left: radius,
+            bottom_right: radius,
+        }
+    }
+
+    pub fn is_uniform(&self) -> Option<f32> {
+        match self.is_uniform_size() {
+            Some(radius) if radius.width == radius.height => Some(radius.width),
+            _ => None
+        }
+    }
+
+    pub fn is_uniform_size(&self) -> Option<LayoutSize> {
         let uniform_radius = self.top_left;
         if self.top_right == uniform_radius &&
            self.bottom_left == uniform_radius &&
            self.bottom_right == uniform_radius {
             Some(uniform_radius)
         } else {
             None
         }
     }
 
     pub fn is_zero(&self) -> bool {
         if let Some(radius) = self.is_uniform() {
-            radius.width == 0.0 && radius.height == 0.0
+            radius == 0.0
         } else {
             false
         }
     }
 }
 
 impl ClipRegion {
     pub fn new(rect: &LayoutRect,
--- a/gfx/webrender_traits/src/display_list.rs
+++ b/gfx/webrender_traits/src/display_list.rs
@@ -1,26 +1,26 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use app_units::Au;
 use std::mem;
 use std::slice;
-use {AuxiliaryLists, AuxiliaryListsDescriptor, BorderDisplayItem, BorderRadius};
-use {BorderSide, BoxShadowClipMode, BoxShadowDisplayItem, BuiltDisplayList};
+use {AuxiliaryLists, AuxiliaryListsDescriptor, BorderDisplayItem};
+use {BoxShadowClipMode, BoxShadowDisplayItem, BuiltDisplayList};
 use {BuiltDisplayListDescriptor, ClipRegion, ComplexClipRegion, ColorF};
 use {DisplayItem, DisplayListMode, ExtendMode, FilterOp, YuvColorSpace};
 use {FontKey, GlyphInstance, GradientDisplayItem, RadialGradientDisplayItem, GradientStop, IframeDisplayItem};
 use {ImageDisplayItem, ImageKey, ImageMask, ImageRendering, ItemRange, MixBlendMode, PipelineId};
 use {PushScrollLayerItem, PushStackingContextDisplayItem, RectangleDisplayItem, ScrollLayerId};
 use {ScrollPolicy, ServoScrollRootId, SpecificDisplayItem, StackingContext, TextDisplayItem};
 use {WebGLContextId, WebGLDisplayItem, YuvImageDisplayItem};
 use {LayoutTransform, LayoutPoint, LayoutRect, LayoutSize};
-use {GlyphOptions, PropertyBinding};
+use {BorderDetails, BorderWidths, GlyphOptions, PropertyBinding};
 
 impl BuiltDisplayListDescriptor {
     pub fn size(&self) -> usize {
         self.display_list_items_size + self.display_items_size
     }
 }
 
 impl BuiltDisplayList {
@@ -181,27 +181,21 @@ impl DisplayListBuilder {
 
             self.list.push(display_item);
         }
     }
 
     pub fn push_border(&mut self,
                        rect: LayoutRect,
                        clip: ClipRegion,
-                       left: BorderSide,
-                       top: BorderSide,
-                       right: BorderSide,
-                       bottom: BorderSide,
-                       radius: BorderRadius) {
+                       widths: BorderWidths,
+                       details: BorderDetails) {
         let item = BorderDisplayItem {
-            left: left,
-            top: top,
-            right: right,
-            bottom: bottom,
-            radius: radius,
+            details: details,
+            widths: widths,
         };
 
         let display_item = DisplayItem {
             item: SpecificDisplayItem::Border(item),
             rect: rect,
             clip: clip,
         };
 
--- a/gfx/webrender_traits/src/types.rs
+++ b/gfx/webrender_traits/src/types.rs
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Every serialisable type is defined in this file to only codegen one file
 // for the serde implementations.
 
 use app_units::Au;
-use euclid::Point2D;
+use euclid::{Point2D, SideOffsets2D};
 use channel::{PayloadSender, MsgSender};
 #[cfg(feature = "nightly")]
 use core::nonzero::NonZero;
 use offscreen_gl_context::{GLContextAttributes, GLLimits};
 use std::fmt;
 use std::marker::PhantomData;
 use std::sync::Arc;
 
@@ -170,36 +170,79 @@ pub struct AuxiliaryLists {
 pub struct AuxiliaryListsDescriptor {
     gradient_stops_size: usize,
     complex_clip_regions_size: usize,
     filters_size: usize,
     glyph_instances_size: usize,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
-pub struct BorderDisplayItem {
+pub struct NormalBorder {
     pub left: BorderSide,
     pub right: BorderSide,
     pub top: BorderSide,
     pub bottom: BorderSide,
     pub radius: BorderRadius,
 }
 
+#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
+pub enum RepeatMode {
+    Stretch,
+    Repeat,
+    Round,
+    Space,
+}
+
+#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
+pub struct NinePatchDescriptor {
+    pub width: u32,
+    pub height: u32,
+    pub slice: SideOffsets2D<u32>,
+}
+
+#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
+pub struct ImageBorder {
+    pub image_key: ImageKey,
+    pub patch: NinePatchDescriptor,
+    pub outset: SideOffsets2D<f32>,
+    pub repeat_horizontal: RepeatMode,
+    pub repeat_vertical: RepeatMode,
+}
+
+#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
+pub enum BorderDetails {
+    Normal(NormalBorder),
+    Image(ImageBorder),
+}
+
+#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
+pub struct BorderDisplayItem {
+    pub widths: BorderWidths,
+    pub details: BorderDetails,
+}
+
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct BorderRadius {
     pub top_left: LayoutSize,
     pub top_right: LayoutSize,
     pub bottom_left: LayoutSize,
     pub bottom_right: LayoutSize,
 }
 
+#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
+pub struct BorderWidths {
+    pub left: f32,
+    pub top: f32,
+    pub right: f32,
+    pub bottom: f32,
+}
+
 #[repr(C)]
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct BorderSide {
-    pub width: f32,
     pub color: ColorF,
     pub style: BorderStyle,
 }
 
 #[repr(u32)]
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub enum BorderStyle {
     None    = 0,
@@ -600,31 +643,74 @@ pub enum YuvColorSpace {
 }
 
 /// An arbitrary identifier for an external image provided by the
 /// application. It must be a unique identifier for each external
 /// image.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
 pub struct ExternalImageId(pub u64);
 
+pub trait BlobImageRenderer: Send {
+    fn request_blob_image(&mut self,
+                            key: ImageKey,
+                            data: Arc<BlobImageData>,
+                            descriptor: &BlobImageDescriptor);
+    fn resolve_blob_image(&mut self, key: ImageKey) -> BlobImageResult;
+}
+
+pub type BlobImageData = Vec<u8>;
+
+#[derive(Copy, Clone, Debug)]
+pub struct BlobImageDescriptor {
+    pub width: u32,
+    pub height: u32,
+    pub format: ImageFormat,
+    pub scale_factor: f32,
+}
+
+pub struct RasterizedBlobImage {
+    pub width: u32,
+    pub height: u32,
+    pub data: Vec<u8>,
+}
+
+#[derive(Clone, Debug)]
+pub enum BlobImageError {
+    Oom,
+    InvalidKey,
+    InvalidData,
+    Other(String),
+}
+
+pub type BlobImageResult = Result<RasterizedBlobImage, BlobImageError>;
+
 #[derive(Clone, Serialize, Deserialize)]
 pub enum ImageData {
     Raw(Arc<Vec<u8>>),
+    Blob(Arc<BlobImageData>),
     ExternalHandle(ExternalImageId),
     ExternalBuffer(ExternalImageId),
 }
 
 impl ImageData {
     pub fn new(bytes: Vec<u8>) -> ImageData {
         ImageData::Raw(Arc::new(bytes))
     }
 
     pub fn new_shared(bytes: Arc<Vec<u8>>) -> ImageData {
         ImageData::Raw(bytes)
     }
+
+    pub fn new_blob_image(commands: Vec<u8>) -> ImageData {
+        ImageData::Blob(Arc::new(commands))
+    }
+
+    pub fn new_shared_blob_image(commands: Arc<Vec<u8>>) -> ImageData {
+        ImageData::Blob(commands)
+    }
 }
 
 #[repr(C)]
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
 pub struct ImageKey(pub u32, pub u32);
 
 #[repr(u32)]
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
@@ -982,30 +1068,30 @@ macro_rules! define_resource_id_struct {
     };
 }
 
 macro_rules! define_resource_id {
     ($name:ident) => {
         define_resource_id_struct!($name);
 
         impl ::serde::Deserialize for $name {
-            fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
+            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
                 where D: ::serde::Deserializer
             {
                 let id = try!(u32::deserialize(deserializer));
                 if id == 0 {
-                    Err(::serde::Error::invalid_value("expected a non-zero value"))
+                    Err(::serde::de::Error::custom("expected a non-zero value"))
                 } else {
                     Ok(unsafe { $name::new(id) })
                 }
             }
         }
 
         impl ::serde::Serialize for $name {
-            fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
+            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                 where S: ::serde::Serializer
             {
                 self.get().serialize(serializer)
             }
         }
 
         impl ::std::fmt::Debug for $name {
             fn fmt(&self, fmt: &mut ::std::fmt::Formatter)
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -4713,20 +4713,20 @@ PresShell::RenderDocument(const nsRect& 
     flags |= PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES;
   }
   if (aFlags & RENDER_USE_WIDGET_LAYERS) {
     // We only support using widget layers on display root's with widgets.
     nsView* view = rootFrame->GetView();
     if (view && view->GetWidget() &&
         nsLayoutUtils::GetDisplayRootFrame(rootFrame) == rootFrame) {
       LayerManager* layerManager = view->GetWidget()->GetLayerManager();
-      // ClientLayerManagers in content processes don't support
-      // taking snapshots.
+      // ClientLayerManagers or WebRenderLayerManagers in content processes
+      // don't support taking snapshots.
       if (layerManager &&
-          (!layerManager->AsClientLayerManager() ||
+          (!layerManager->AsKnowsCompositor() ||
            XRE_IsParentProcess())) {
         flags |= PaintFrameFlags::PAINT_WIDGET_LAYERS;
       }
     }
   }
   if (!(aFlags & RENDER_CARET)) {
     wouldFlushRetainedLayers = true;
     flags |= PaintFrameFlags::PAINT_HIDE_CARET;
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -1364,49 +1364,85 @@ nsCSSRendering::EndFrameTreesLocked()
 {
   NS_ASSERTION(gFrameTreeLockCount > 0, "Unbalanced EndFrameTreeLocked");
   --gFrameTreeLockCount;
   if (gFrameTreeLockCount == 0) {
     gInlineBGData->Reset();
   }
 }
 
+bool
+nsCSSRendering::HasBoxShadowNativeTheme(nsIFrame* aFrame,
+                                        bool& aMaybeHasBorderRadius)
+{
+  const nsStyleDisplay* styleDisplay = aFrame->StyleDisplay();
+  nsITheme::Transparency transparency;
+  if (aFrame->IsThemed(styleDisplay, &transparency)) {
+    aMaybeHasBorderRadius = false;
+    // For opaque (rectangular) theme widgets we can take the generic
+    // border-box path with border-radius disabled.
+    return transparency != nsITheme::eOpaque;
+  }
+
+  aMaybeHasBorderRadius = true;
+  return false;
+}
+
+gfx::Color
+nsCSSRendering::GetShadowColor(nsCSSShadowItem* aShadow,
+                               nsIFrame* aFrame,
+                               float aOpacity)
+{
+  // Get the shadow color; if not specified, use the foreground color
+  nscolor shadowColor;
+  if (aShadow->mHasColor)
+    shadowColor = aShadow->mColor;
+  else
+    shadowColor = aFrame->StyleColor()->mColor;
+
+  Color color = Color::FromABGR(shadowColor);
+  color.a *= aOpacity;
+  return color;
+}
+
+nsRect
+nsCSSRendering::GetShadowRect(const nsRect aFrameArea,
+                              bool aNativeTheme,
+                              nsIFrame* aForFrame)
+{
+  nsRect frameRect = aNativeTheme ?
+    aForFrame->GetVisualOverflowRectRelativeToSelf() + aFrameArea.TopLeft() :
+    aFrameArea;
+  Sides skipSides = aForFrame->GetSkipSides();
+  frameRect = ::BoxDecorationRectForBorder(aForFrame, frameRect, skipSides);
+
+  // Explicitly do not need to account for the spread radius here
+  // Webrender does it for us or PaintBoxShadow will for non-WR
+  return frameRect;
+}
+
 void
 nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
                                     nsRenderingContext& aRenderingContext,
                                     nsIFrame* aForFrame,
                                     const nsRect& aFrameArea,
                                     const nsRect& aDirtyRect,
                                     float aOpacity)
 {
   DrawTarget& aDrawTarget = *aRenderingContext.GetDrawTarget();
   nsCSSShadowArray* shadows = aForFrame->StyleEffects()->mBoxShadow;
   if (!shadows)
     return;
 
   bool hasBorderRadius;
-  bool nativeTheme; // mutually exclusive with hasBorderRadius
+  // mutually exclusive with hasBorderRadius
+  bool nativeTheme = HasBoxShadowNativeTheme(aForFrame, hasBorderRadius);
   const nsStyleDisplay* styleDisplay = aForFrame->StyleDisplay();
-  nsITheme::Transparency transparency;
-  if (aForFrame->IsThemed(styleDisplay, &transparency)) {
-    // We don't respect border-radius for native-themed widgets
-    hasBorderRadius = false;
-    // For opaque (rectangular) theme widgets we can take the generic
-    // border-box path with border-radius disabled.
-    nativeTheme = transparency != nsITheme::eOpaque;
-  } else {
-    nativeTheme = false;
-    hasBorderRadius = true; // we'll update this below
-  }
-
-  nsRect frameRect = nativeTheme ?
-    aForFrame->GetVisualOverflowRectRelativeToSelf() + aFrameArea.TopLeft() :
-    aFrameArea;
-  Sides skipSides = aForFrame->GetSkipSides();
-  frameRect = ::BoxDecorationRectForBorder(aForFrame, frameRect, skipSides);
+
+  nsRect frameRect = GetShadowRect(aFrameArea, nativeTheme, aForFrame);
 
   // Get any border radius, since box-shadow must also have rounded corners if
   // the frame does.
   RectCornerRadii borderRadii;
   const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
   if (hasBorderRadius) {
     nscoord twipsRadii[8];
     NS_ASSERTION(aFrameArea.Size() == aForFrame->VisualBorderRectRelativeToSelf().Size(),
@@ -1460,25 +1496,17 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
     shadowRectPlusBlur.Inflate(
       nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel));
 
     Rect shadowGfxRectPlusBlur =
       NSRectToRect(shadowRectPlusBlur, twipsPerPixel);
     shadowGfxRectPlusBlur.RoundOut();
     MaybeSnapToDevicePixels(shadowGfxRectPlusBlur, aDrawTarget, true);
 
-    // Set the shadow color; if not specified, use the foreground color
-    nscolor shadowColor;
-    if (shadowItem->mHasColor)
-      shadowColor = shadowItem->mColor;
-    else
-      shadowColor = aForFrame->StyleColor()->mColor;
-
-    Color gfxShadowColor(Color::FromABGR(shadowColor));
-    gfxShadowColor.a *= aOpacity;
+    Color gfxShadowColor = GetShadowColor(shadowItem, aForFrame, aOpacity);
 
     if (nativeTheme) {
       nsContextBoxBlur blurringArea;
 
       // When getting the widget shape from the native theme, we're going
       // to draw the widget into the shadow surface to create a mask.
       // We need to ensure that there actually *is* a shadow surface
       // and that we're not going to draw directly into renderContext.
@@ -1542,16 +1570,17 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
           AppendRectToPath(builder, innerClipRect);
         }
         RefPtr<Path> path = builder->Finish();
         renderContext->Clip(path);
       }
 
       // Clip the shadow so that we only get the part that applies to aForFrame.
       nsRect fragmentClip = shadowRectPlusBlur;
+      Sides skipSides = aForFrame->GetSkipSides();
       if (!skipSides.IsEmpty()) {
         if (skipSides.Left()) {
           nscoord xmost = fragmentClip.XMost();
           fragmentClip.x = aFrameArea.x;
           fragmentClip.width = xmost - fragmentClip.x;
         }
         if (skipSides.Right()) {
           nscoord xmost = fragmentClip.XMost();
@@ -1735,21 +1764,17 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
     DrawTarget* drawTarget = renderContext->GetDrawTarget();
 
     // Clip the context to the area of the frame's padding rect, so no part of the
     // shadow is painted outside. Also cut out anything beyond where the inset shadow
     // will be.
     Rect shadowGfxRect = NSRectToRect(paddingRect, twipsPerPixel);
     shadowGfxRect.Round();
 
-    // Set the shadow color; if not specified, use the foreground color
-    Color shadowColor = Color::FromABGR(shadowItem->mHasColor ?
-                                          shadowItem->mColor :
-                                          aForFrame->StyleColor()->mColor);
-
+    Color shadowColor = GetShadowColor(shadowItem, aForFrame, 1.0);
     renderContext->Save();
 
     // This clips the outside border radius.
     // clipRectRadii is the border radius inside the inset shadow.
     if (hasBorderRadius) {
       RefPtr<Path> roundedRect =
         MakePathForRoundedRect(*drawTarget, shadowGfxRect, innerRadii);
       renderContext->Clip(roundedRect);
--- a/layout/painting/nsCSSRendering.h
+++ b/layout/painting/nsCSSRendering.h
@@ -349,16 +349,17 @@ struct nsBackgroundLayerState {
   /**
    * The background-repeat property space keyword computes the
    * repeat size which is image size plus spacing.
    */
   nsSize mRepeatSize;
 };
 
 struct nsCSSRendering {
+  typedef mozilla::gfx::Color Color;
   typedef mozilla::gfx::CompositionOp CompositionOp;
   typedef mozilla::gfx::DrawTarget DrawTarget;
   typedef mozilla::gfx::Float Float;
   typedef mozilla::gfx::Point Point;
   typedef mozilla::gfx::Rect Rect;
   typedef mozilla::gfx::Size Size;
   typedef mozilla::gfx::RectCornerRadii RectCornerRadii;
   typedef mozilla::image::DrawResult DrawResult;
@@ -374,16 +375,27 @@ struct nsCSSRendering {
    */
   static void Shutdown();
   
   static void PaintBoxShadowInner(nsPresContext* aPresContext,
                                   nsRenderingContext& aRenderingContext,
                                   nsIFrame* aForFrame,
                                   const nsRect& aFrameArea);
 
+  static nsRect GetShadowRect(const nsRect aFrameArea,
+                              bool aNativeTheme,
+                              nsIFrame* aForFrame);
+  static mozilla::gfx::Color GetShadowColor(nsCSSShadowItem* aShadow,
+                                   nsIFrame* aFrame,
+                                   float aOpacity);
+  // Returns if the frame has a themed frame.
+  // aMaybeHasBorderRadius will return false if we can early detect
+  // that we don't have a border radius.
+  static bool HasBoxShadowNativeTheme(nsIFrame* aFrame,
+                                      bool& aMaybeHasBorderRadius);
   static void PaintBoxShadowOuter(nsPresContext* aPresContext,
                                   nsRenderingContext& aRenderingContext,
                                   nsIFrame* aForFrame,
                                   const nsRect& aFrameArea,
                                   const nsRect& aDirtyRect,
                                   float aOpacity = 1.0);
 
   static void ComputePixelRadii(const nscoord *aAppUnitsRadii,
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -4771,55 +4771,64 @@ nsDisplayBoxShadowOuter::CreateWebRender
   nsRegion visible = aLayer->GetVisibleRegion().ToAppUnits(appUnitsPerDevPixel);
 
   ComputeDisjointRectangles(visible, &rects);
 
   nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
   if (!shadows)
     return;
 
+  bool hasBorderRadius;
+  bool nativeTheme = nsCSSRendering::HasBoxShadowNativeTheme(mFrame,
+                                                             hasBorderRadius);
+
   // Everything here is in app units, change to device units.
   for (uint32_t i = 0; i < rects.Length(); ++i) {
     Rect clipRect = NSRectToRect(rects[i], appUnitsPerDevPixel);
-    Rect gfxBorderRect = NSRectToRect(borderRect, appUnitsPerDevPixel);
-
-    Rect deviceClipRect = aLayer->RelativeToParent(clipRect);
-    Rect deviceBoxRect = aLayer->RelativeToParent(gfxBorderRect);
-
-    for (uint32_t j = shadows->Length(); j > 0; --j) {
-      nsCSSShadowItem* shadowItem = shadows->ShadowAt(j - 1);
-      nscoord blurRadius = shadowItem->mRadius;
-      float gfxBlurRadius = blurRadius / appUnitsPerDevPixel;
-
-      // TODO: Have to refactor our nsCSSRendering
-      // to get the acual rects correct.
-      nscolor shadowColor;
-      if (shadowItem->mHasColor)
-        shadowColor = shadowItem->mColor;
-      else
-        shadowColor = mFrame->StyleColor()->mColor;
-
-      Color gfxShadowColor(Color::FromABGR(shadowColor));
-      gfxShadowColor.a *= mOpacity;
-
-      WrPoint offset;
-      offset.x = shadowItem->mXOffset;
-      offset.y = shadowItem->mYOffset;
+    nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
+
+    for (uint32_t j = shadows->Length(); j  > 0; j--) {
+      nsCSSShadowItem* shadow = shadows->ShadowAt(j - 1);
+      // Don't need the full size of the shadow rect like we do in
+      // nsCSSRendering since WR takes care of calculations for blur
+      // and spread radius.
+      nsRect shadowRect = nsCSSRendering::GetShadowRect(borderRect,
+                                                        nativeTheme,
+                                                        mFrame);
+      gfx::Color shadowColor = nsCSSRendering::GetShadowColor(shadow,
+                                                              mFrame,
+                                                              mOpacity);
+      shadowRect.MoveBy(shadow->mXOffset, shadow->mYOffset);
+
+      // Now translate everything to device pixels.
+      Point shadowOffset;
+      shadowOffset.x = (shadow->mXOffset / appUnitsPerDevPixel);
+      shadowOffset.y = (shadow->mYOffset / appUnitsPerDevPixel);
+
+      Rect deviceBoxRect = NSRectToRect(shadowRect, appUnitsPerDevPixel);
+      deviceBoxRect = aLayer->RelativeToParent(deviceBoxRect);
+
+      Rect deviceClipRect = aLayer->RelativeToParent(clipRect + shadowOffset);
+
+      float blurRadius = shadow->mRadius / appUnitsPerDevPixel;
+      // TODO: Calculate the border radius here.
+      float borderRadius = 0.0;
+      float spreadRadius = shadow->mSpread / appUnitsPerDevPixel;
 
       aCommands.AppendElement(OpDPPushBoxShadow(
                               wr::ToWrRect(deviceBoxRect),
                               wr::ToWrRect(deviceClipRect),
                               wr::ToWrRect(deviceBoxRect),
-                              offset,
-                              wr::ToWrColor(gfxShadowColor),
-                              gfxBlurRadius,
-                              0,
-                              0,
+                              wr::ToWrPoint(shadowOffset),
+                              wr::ToWrColor(shadowColor),
+                              blurRadius,
+                              spreadRadius,
+                              borderRadius,
                               WrBoxShadowClipMode::Outset
-      ));
+                              ));
     }
   }
 }
 
 void
 nsDisplayBoxShadowOuter::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                                    const nsDisplayItemGeometry* aGeometry,
                                                    nsRegion* aInvalidRegion)
--- a/media/webrtc/trunk/webrtc/build/common.gypi
+++ b/media/webrtc/trunk/webrtc/build/common.gypi
@@ -321,19 +321,16 @@
               '-Woverloaded-virtual',
             ],
           }],
           ['clang==1', {
             'cflags': [
               '-Wimplicit-fallthrough',
               '-Wthread-safety',
             ],
-            'cflags_mozilla': [
-              '-Wthread-safety',
-            ],
           }],
         ],
       }],
       ['target_arch=="arm64"', {
         'defines': [
           'WEBRTC_ARCH_ARM64',
           'WEBRTC_HAS_NEON',
         ],
--- a/security/manager/ssl/StaticHPKPins.h
+++ b/security/manager/ssl/StaticHPKPins.h
@@ -1152,9 +1152,9 @@ static const TransportSecurityPreload kP
   { "za.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
   { "zh.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
 };
 
 // Pinning Preload List Length = 477;
 
 static const int32_t kUnknownId = -1;
 
-static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1496246555187000);
+static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1496331215141000);
--- a/security/manager/ssl/nsSTSPreloadList.errors
+++ b/security/manager/ssl/nsSTSPreloadList.errors
@@ -1,16 +1,17 @@
 007sascha.de: max-age too low: 3600
 00f.net: did not receive HSTS header
 020wifi.nl: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 0p.no: did not receive HSTS header
 0x0a.net: could not connect to host
 0x1337.eu: could not connect to host
 0x44.net: did not receive HSTS header
 0xa.in: could not connect to host
+0xacab.org: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 0xb612.org: could not connect to host
 0xf00.ch: did not receive HSTS header
 100dayloans.com: max-age too low: 0
 1018hosting.nl: did not receive HSTS header
 1022996493.rsc.cdn77.org: could not connect to host
 10seos.com: did not receive HSTS header
 10tacle.io: could not connect to host
 123plons.nl: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
@@ -39,25 +40,25 @@ 33drugstore.com: did not receive HSTS he
 360ds.co.in: could not connect to host
 360gradus.com: did not receive HSTS header
 365.or.jp: did not receive HSTS header
 3chit.cf: could not connect to host
 3click-loan.com: could not connect to host
 3sreporting.com: did not receive HSTS header
 3yearloans.com: max-age too low: 0
 404.sh: max-age too low: 0
-404404.info: could not connect to host
 41844.de: could not connect to host
 420dongstorm.com: could not connect to host
 42ms.org: could not connect to host
 4455software.com: did not receive HSTS header
 4679.space: could not connect to host
 47ronin.com: did not receive HSTS header
 4cclothing.com: could not connect to host
 4elements.com: did not receive HSTS header
+4eyes.ch: did not receive HSTS header
 4mm.org: did not receive HSTS header
 4sqsu.eu: could not connect to host
 50millionablaze.org: did not receive HSTS header
 540.co: did not receive HSTS header
 56ct.com: could not connect to host
 60ych.net: did not receive HSTS header
 6120.eu: did not receive HSTS header
 7kovrikov.ru: did not receive HSTS header
@@ -146,16 +147,17 @@ ahabingo.com: did not receive HSTS heade
 ahmedabadflowermall.com: did not receive HSTS header
 ahoynetwork.com: could not connect to host
 ahri.ovh: could not connect to host
 aidanwoods.com: did not receive HSTS header
 airbnb.com: did not receive HSTS header
 aircomms.com: did not receive HSTS header
 airproto.com: did not receive HSTS header
 aishnair.com: could not connect to host
+aisle3.space: could not connect to host
 aiticon.de: did not receive HSTS header
 aiw-thkoeln.online: could not connect to host
 ajmahal.com: could not connect to host
 akclinics.org: did not receive HSTS header
 akombakom.net: did not receive HSTS header
 akselimedia.fi: did not receive HSTS header
 akutun.cl: could not connect to host
 al-shami.net: could not connect to host
@@ -304,16 +306,19 @@ asc16.com: could not connect to host
 asdpress.cn: could not connect to host
 ashlane-cottages.com: could not connect to host
 ashutoshmishra.org: did not receive HSTS header
 asianodor.com: could not connect to host
 askfit.cz: did not receive HSTS header
 asm-x.com: could not connect to host
 asmui.ga: could not connect to host
 asmui.ml: could not connect to host
+asr.li: could not connect to host
+asr.rocks: could not connect to host
+asr.solar: could not connect to host
 asrob.eu: did not receive HSTS header
 ass.org.au: did not receive HSTS header
 assdecoeur.org: could not connect to host
 assekuranzjobs.de: could not connect to host
 asset-alive.com: did not receive HSTS header
 asset-alive.net: did not receive HSTS header
 astrath.net: could not connect to host
 astrolpost.com: could not connect to host
@@ -322,17 +327,16 @@ asuhe.win: did not receive HSTS header
 atavio.at: could not connect to host
 atavio.ch: could not connect to host
 atavio.de: did not receive HSTS header
 atbeckett.com: did not receive HSTS header
 athaliasoft.com: did not receive HSTS header
 athenelive.com: could not connect to host
 athul.xyz: did not receive HSTS header
 atlex.nl: did not receive HSTS header
-atlseccon.com: did not receive HSTS header
 atomik.pro: could not connect to host
 atop.io: could not connect to host
 attimidesigns.com: did not receive HSTS header
 au.search.yahoo.com: max-age too low: 172800
 aubiosales.com: did not receive HSTS header
 aucubin.moe: could not connect to host
 audiovisualdevices.com.au: did not receive HSTS header
 aufmerksamkeitsstudie.com: could not connect to host
@@ -443,22 +447,21 @@ berger.work: did not receive HSTS header
 berlatih.com: could not connect to host
 berlinleaks.com: could not connect to host
 bermytraq.bm: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 berrymark.be: max-age too low: 0
 besixdouze.world: could not connect to host
 bestbeards.ca: could not connect to host
 bestcellular.com: did not receive HSTS header
 betafive.net: could not connect to host
-betaworx.de: did not receive HSTS header
-betaworx.eu: did not receive HSTS header
 betcafearena.ro: did not receive HSTS header
 betnet.fr: could not connect to host
 betplanning.it: did not receive HSTS header
 bets.de: did not receive HSTS header
+bettercrypto.org: could not connect to host
 bettween.com: could not connect to host
 betz.ro: did not receive HSTS header
 bevapehappy.com: did not receive HSTS header
 beyuna.co.uk: did not receive HSTS header
 beyuna.eu: did not receive HSTS header
 beyuna.nl: did not receive HSTS header
 bezorg.ninja: could not connect to host
 bf.am: max-age too low: 0
@@ -536,24 +539,23 @@ bnhlibrary.com: could not connect to hos
 bobiji.com: did not receive HSTS header
 bodo-wolff.de: could not connect to host
 bodyblog.nl: did not receive HSTS header
 bodybuilding-legends.com: could not connect to host
 bodyweightsolution.com: could not connect to host
 boensou.com: did not receive HSTS header
 bogosity.se: could not connect to host
 bohan.life: could not connect to host
-bombsquad.studio: could not connect to host
 bonapp.restaurant: could not connect to host
 bonfi.net: did not receive HSTS header
 bonigo.de: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 bonitabrazilian.co.nz: did not receive HSTS header
 bookcelerator.com: did not receive HSTS header
 booked.holiday: could not connect to host
-bookourdjs.com: could not connect to host
+bookourdjs.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 boomerang.com: could not connect to host
 boosterlearnpro.com: did not receive HSTS header
 bootjp.me: did not receive HSTS header
 boringsecurity.net: could not connect to host
 boris.one: did not receive HSTS header
 borisbesemer.com: could not connect to host
 botox.bz: did not receive HSTS header
 bouwbedrijfpurmerend.nl: did not receive HSTS header
@@ -592,21 +594,22 @@ buchheld.at: did not receive HSTS header
 bucket.tk: could not connect to host
 budgetthostels.nl: did not receive HSTS header
 budskap.eu: could not connect to host
 bugtrack.io: did not receive HSTS header
 buhler.pro: did not receive HSTS header
 buildci.asia: could not connect to host
 buildsaver.co.za: did not receive HSTS header
 built.by: did not receive HSTS header
-builtritetrailerplans.com: could not connect to host
+builtritetrailerplans.com: did not receive HSTS header
 bulletpoint.cz: did not receive HSTS header
 bulmafox.com: could not connect to host
 bumarkamoda.com: could not connect to host
 bunaken.asia: could not connect to host
+bunbomenu.de: could not connect to host
 burian-server.cz: could not connect to host
 burrow.ovh: could not connect to host
 burtrum.me: could not connect to host
 burtrum.top: could not connect to host
 business.lookout.com: could not connect to host
 businesshosting.nl: did not receive HSTS header
 businessloanstoday.com: max-age too low: 0
 busold.ws: could not connect to host
@@ -623,16 +626,17 @@ bypassed.press: could not connect to hos
 bypassed.today: did not receive HSTS header
 bypassed.works: did not receive HSTS header
 bypassed.world: did not receive HSTS header
 bypro.xyz: could not connect to host
 bysymphony.com: max-age too low: 0
 byte.wtf: did not receive HSTS header
 bytepark.de: did not receive HSTS header
 bytesund.biz: could not connect to host
+c0rn3j.com: could not connect to host
 c1yd3i.me: could not connect to host
 c3b.info: could not connect to host
 cabarave.com: could not connect to host
 cabusar.fr: could not connect to host
 caconnect.org: could not connect to host
 cadao.me: did not receive HSTS header
 cafe-scientifique.org.ec: could not connect to host
 caim.cz: did not receive HSTS header
@@ -657,16 +661,17 @@ cannyfoxx.me: could not connect to host
 canyonshoa.com: did not receive HSTS header
 capecycles.co.za: did not receive HSTS header
 capeyorkfire.com.au: did not receive HSTS header
 captchatheprize.com: could not connect to host
 capturethepen.co.uk: could not connect to host
 car-navi.ph: did not receive HSTS header
 carano-service.de: did not receive HSTS header
 caraudio69.cz: could not connect to host
+carck.co.uk: did not receive HSTS header
 cardloan-manual.net: could not connect to host
 cardoni.net: did not receive HSTS header
 cardstream.com: did not receive HSTS header
 cardurl.com: did not receive HSTS header
 carey.li: could not connect to host
 cargobay.net: could not connect to host
 caringladies.org: could not connect to host
 carlandfaith.com: did not receive HSTS header
@@ -729,17 +734,16 @@ chcemvediet.sk: max-age too low: 1555200
 cheapdns.org: could not connect to host
 chebedara.com: could not connect to host
 checkout.google.com: did not receive HSTS header (error ignored - included regardless)
 cheerflow.com: could not connect to host
 cheesetart.my: could not connect to host
 cheetah85.de: could not connect to host
 chejianer.cn: did not receive HSTS header
 chensir.net: could not connect to host
-chepaofen.com: could not connect to host
 cherysunzhang.com: max-age too low: 7776000
 chihiro.xyz: could not connect to host
 chijiokeindustries.co.uk: could not connect to host
 childcaresolutionscny.org: did not receive HSTS header
 chinacdn.org: could not connect to host
 chinawhale.com: did not receive HSTS header
 chirgui.eu: could not connect to host
 chm.vn: did not receive HSTS header
@@ -773,40 +777,38 @@ ciplanutrition.com: did not receive HSTS
 circara.com: did not receive HSTS header
 ciscommerce.net: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 citiagent.cz: could not connect to host
 cityoflaurel.org: did not receive HSTS header
 clara-baumert.de: could not connect to host
 classicsandexotics.com: did not receive HSTS header
 classicspublishing.com: could not connect to host
 clcleaningco.com: could not connect to host
-cldly.com: could not connect to host
 cleanexperts.co.uk: could not connect to host
 cleaningsquad.ca: could not connect to host
 cleanmta.com: could not connect to host
 clearc.tk: could not connect to host
 clemovementlaw.com: could not connect to host
 clerkendweller.uk: could not connect to host
 clickandgo.com: did not receive HSTS header
 clickandshoot.nl: did not receive HSTS header
 clickgram.biz: could not connect to host
 clientsecure.me: could not connect to host
-clint.id.au: max-age too low: 0
+clint.id.au: could not connect to host
 clintonbloodworth.com: could not connect to host
 clintonbloodworth.io: could not connect to host
 clintwilson.technology: max-age too low: 2592000
 clip.mx: did not receive HSTS header
 cloud.wtf: could not connect to host
 cloudapi.vc: could not connect to host
 cloudcert.org: did not receive HSTS header
 cloudcy.net: could not connect to host
 clouddesktop.co.nz: could not connect to host
 cloudey.net: did not receive HSTS header
 cloudflare.com: did not receive HSTS header
-cloudily.com: could not connect to host
 cloudimag.es: could not connect to host
 cloudlink.club: could not connect to host
 cloudns.com.au: could not connect to host
 cloudspotterapp.com: did not receive HSTS header
 cloudstoragemaus.com: could not connect to host
 cloudstorm.me: could not connect to host
 cloudwalk.io: did not receive HSTS header
 cloverleaf.net: max-age too low: 0
@@ -819,30 +821,30 @@ cmci.dk: did not receive HSTS header
 cmlachapelle.ch: did not receive HSTS header
 cmlancy.ch: did not receive HSTS header
 cmlignon.ch: did not receive HSTS header
 cmplainpalais.ch: did not receive HSTS header
 cmsbattle.com: could not connect to host
 cmscafe.ru: did not receive HSTS header
 cn.search.yahoo.com: did not receive HSTS header
 cni-certing.it: max-age too low: 0
+cnwage.com: could not connect to host
 co50.com: did not receive HSTS header
 cocaine-import.agency: could not connect to host
 cocktailfuture.fr: could not connect to host
 codabix.com: did not receive HSTS header
 codabix.de: could not connect to host
 codabix.net: could not connect to host
 code.google.com: did not receive HSTS header (error ignored - included regardless)
 codeco.pw: could not connect to host
 codecontrollers.de: could not connect to host
 codeforce.io: could not connect to host
 codelayer.ca: could not connect to host
 codemonkeyrawks.net: did not receive HSTS header
 codepoet.de: could not connect to host
-codepult.com: could not connect to host
 codepx.com: did not receive HSTS header
 codewiththepros.org: could not connect to host
 codiva.io: max-age too low: 2592000
 codymoniz.com: could not connect to host
 coffeeetc.co.uk: did not receive HSTS header
 coffeestrategies.com: max-age too low: 2592000
 coiffeurschnittstelle.ch: did not receive HSTS header
 coindam.com: could not connect to host
@@ -884,17 +886,16 @@ controlcenter.gigahost.dk: did not recei
 coolchevy.org.ua: did not receive HSTS header
 cor-ser.es: could not connect to host
 coralproject.net: did not receive HSTS header
 coralrosado.com.br: did not receive HSTS header
 cordial-restaurant.com: did not receive HSTS header
 core.mx: could not connect to host
 core4system.de: could not connect to host
 corenetworking.de: could not connect to host
-corgicloud.com: did not receive HSTS header
 cormactagging.ie: could not connect to host
 cormilu.com.br: did not receive HSTS header
 correctpaardbatterijnietje.nl: did not receive HSTS header
 corruption-mc.net: could not connect to host
 corruption-rsps.net: could not connect to host
 corruption-server.net: could not connect to host
 count.sh: could not connect to host
 couragewhispers.ca: did not receive HSTS header
@@ -926,24 +927,23 @@ crowdcurity.com: did not receive HSTS he
 crowdjuris.com: could not connect to host
 crtvmgmt.com: could not connect to host
 crudysql.com: could not connect to host
 crufad.org: did not receive HSTS header
 cruzr.xyz: could not connect to host
 crypt.guru: could not connect to host
 crypticshell.co.uk: could not connect to host
 cryptify.eu: could not connect to host
-cryptobin.co: could not connect to host
 cryptobin.org: could not connect to host
 cryptojar.io: did not receive HSTS header
 cryptoki.fr: max-age too low: 7776000
 cryptolab.pro: could not connect to host
 cryptolab.tk: could not connect to host
 cryptopartyatx.org: could not connect to host
-cryptopush.com: did not receive HSTS header
+cryptopush.com: could not connect to host
 crysadm.com: max-age too low: 1
 crystalclassics.co.uk: did not receive HSTS header
 csapak.com: max-age too low: 0
 csawctf.poly.edu: could not connect to host
 csfs.org.uk: could not connect to host
 csgodicegame.com: did not receive HSTS header
 csgoelemental.com: could not connect to host
 csgokings.eu: could not connect to host
@@ -1043,16 +1043,17 @@ debiton.dk: could not connect to host
 debtkit.co.uk: did not receive HSTS header
 decafu.co: could not connect to host
 decesus.com: could not connect to host
 decibelios.li: could not connect to host
 deco.me: could not connect to host
 dedicatutiempo.es: could not connect to host
 deepcovelabs.net: could not connect to host
 deepearth.uk: did not receive HSTS header
+deetz.nl: could not connect to host
 deetzen.de: did not receive HSTS header
 defiler.tk: could not connect to host
 degroetenvanrosaline.nl: did not receive HSTS header
 deight.co: could not connect to host
 dekasan.ru: could not connect to host
 delayrefunds.co.uk: could not connect to host
 deliverance.co.uk: could not connect to host
 deltaconcepts.de: did not receive HSTS header
@@ -1085,17 +1086,16 @@ deviltracks.net: could not connect to ho
 devincrow.me: could not connect to host
 devopsconnected.com: could not connect to host
 devtub.com: did not receive HSTS header
 devuan.org: did not receive HSTS header
 dewin.io: could not connect to host
 dhpcs.com: did not receive HSTS header
 dhpiggott.net: did not receive HSTS header
 diablotine.rocks: could not connect to host
-diamante.ro: could not connect to host
 diarbag.us: did not receive HSTS header
 diasp.cz: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 dick.red: could not connect to host
 die-partei-reutlingen.de: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 diedrich.co: did not receive HSTS header
 digidroom.be: did not receive HSTS header
 digioccumss.ddns.net: could not connect to host
 digitalbank.kz: could not connect to host
@@ -1110,16 +1110,17 @@ discovery.lookout.com: did not receive H
 dislocated.de: did not receive HSTS header
 disowned.net: max-age too low: 0
 dissimulo.me: could not connect to host
 dittvertshus.no: could not connect to host
 diva-ey.com: could not connect to host
 dizihocasi.com: could not connect to host
 dizorg.net: could not connect to host
 dj4et.de: could not connect to host
+djlnetworks.co.uk: did not receive HSTS header
 djz4music.com: did not receive HSTS header
 dl.google.com: did not receive HSTS header (error ignored - included regardless)
 dlc.viasinc.com: could not connect to host
 dlemper.de: did not receive HSTS header
 dn42.eu: could not connect to host
 dns.google.com: did not receive HSTS header (error ignored - included regardless)
 dnsknowledge.com: did not receive HSTS header
 do-do.tk: could not connect to host
@@ -1152,19 +1153,22 @@ doridian.org: could not connect to host
 dossplumbing.co.za: did not receive HSTS header
 dotadata.me: could not connect to host
 dovecotadmin.org: could not connect to host
 dovetailnow.com: could not connect to host
 download.jitsi.org: did not receive HSTS header
 downsouthweddings.com.au: did not receive HSTS header
 doyoucheck.com: did not receive HSTS header
 dpratt.de: did not receive HSTS header
+dpsg-roden.de: could not connect to host
 dragonisles.net: could not connect to host
 dragons-of-highlands.cz: could not connect to host
-dragontrainingmobilezoo.com.au: max-age too low: 0
+dragontrainingmobilezoo.com.au: could not connect to host
+drakeanddragon.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
+drakefortreasurer.sexy: could not connect to host
 draw.uy: could not connect to host
 drdevil.ru: could not connect to host
 drdim.ru: could not connect to host
 dreadbyte.com: could not connect to host
 drewgle.net: could not connect to host
 drhopeson.com: could not connect to host
 drishti.guru: could not connect to host
 drive.google.com: did not receive HSTS header (error ignored - included regardless)
@@ -1176,34 +1180,33 @@ drumbandesperanto.nl: could not connect 
 ds-christiansen.de: did not receive HSTS header
 dshiv.io: could not connect to host
 dubrovskiy.net: could not connect to host
 dubrovskiy.pro: could not connect to host
 duesee.org: could not connect to host
 dullsir.com: did not receive HSTS header
 duria.de: max-age too low: 3600
 dustri.org: did not receive HSTS header
-dutchessuganda.com: did not receive HSTS header
 dutchrank.com: could not connect to host
 dwhd.org: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 dworzak.ch: could not connect to host
 dycontrol.de: could not connect to host
 dylanscott.com.au: did not receive HSTS header
+dymersion.com: did not receive HSTS header
 dynamic-innovations.net: could not connect to host
 dzimejl.sk: did not receive HSTS header
 dzlibs.io: could not connect to host
-dzndk.net: could not connect to host
 dzndk.org: could not connect to host
 e-aut.net: did not receive HSTS header
 e-deca2.org: did not receive HSTS header
 e-sa.com: did not receive HSTS header
 e3amn2l.com: could not connect to host
 earlybirdsnacks.com: could not connect to host
 earthrise16.com: could not connect to host
-easez.net: did not receive HSTS header
+easez.net: could not connect to host
 easychiller.org: could not connect to host
 easyhaul.com: did not receive HSTS header
 eatlowcarb.de: did not receive HSTS header
 eauclairecommerce.com: could not connect to host
 ebankcbt.com: could not connect to host
 ebecs.com: did not receive HSTS header
 ebermannstadt.de: max-age too low: 0
 ebonyriddle.com: could not connect to host
@@ -1241,16 +1244,17 @@ ekbanden.nl: could not connect to host
 elaintehtaat.fi: did not receive HSTS header
 elan-organics.com: did not receive HSTS header
 elanguest.pl: could not connect to host
 elanguest.ro: did not receive HSTS header
 elanguest.ru: did not receive HSTS header
 elbetech.net: could not connect to host
 electricianforum.co.uk: did not receive HSTS header
 electromc.com: could not connect to host
+elektronring.com: could not connect to host
 elemenx.com: did not receive HSTS header
 elemprendedor.com.ve: could not connect to host
 elenag.ga: could not connect to host
 elenoon.ir: did not receive HSTS header
 elgacien.de: could not connect to host
 elimdengelen.com: did not receive HSTS header
 elitefishtank.com: could not connect to host
 elliotgluck.com: could not connect to host
@@ -1273,17 +1277,16 @@ empleostampico.com: did not receive HSTS
 enaah.de: could not connect to host
 enaia.fr: could not connect to host
 enargia.jp: max-age too low: 0
 encode.host: did not receive HSTS header
 encode.space: did not receive HSTS header
 encoder.pw: could not connect to host
 encontrebarato.com.br: did not receive HSTS header
 encrypted.google.com: did not receive HSTS header (error ignored - included regardless)
-encryptedaudience.com: could not connect to host
 end.pp.ua: could not connect to host
 endlessdark.net: max-age too low: 600
 endlessdiy.ca: could not connect to host
 endlesstone.com: did not receive HSTS header
 enersec.co.uk: could not connect to host
 engelwerbung.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 enigmacpt.com: did not receive HSTS header
 enigmail.net: did not receive HSTS header
@@ -1307,17 +1310,16 @@ ephry.com: could not connect to host
 epoxate.com: could not connect to host
 eq8.net.au: could not connect to host
 equate.net.au: max-age too low: 3600
 equatetechnologies.com.au: max-age too low: 3600
 equilibre-yoga-jennifer-will.com: could not connect to host
 erawanarifnugroho.com: did not receive HSTS header
 eressea.xyz: could not connect to host
 eridanus.uk: could not connect to host
-erikhubers.nl: could not connect to host
 ernaehrungsberatung-rapperswil.ch: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 ernaehrungsberatung-zurich.ch: could not connect to host
 ernesto.at: could not connect to host
 eromixx.com: did not receive HSTS header
 erotalia.es: could not connect to host
 eroticen.com: did not receive HSTS header
 erotische-aanbiedingen.nl: could not connect to host
 errlytics.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
@@ -1356,17 +1358,16 @@ evites.me: could not connect to host
 evomon.com: could not connect to host
 evossd.tk: could not connect to host
 ewuchuan.com: could not connect to host
 excelgum.ca: did not receive HSTS header
 exfiles.cz: did not receive HSTS header
 exgravitus.com: could not connect to host
 exitus.jp: max-age too low: 0
 exno.co: could not connect to host
-expatads.com: could not connect to host
 expertmile.com: did not receive HSTS header
 expoundite.net: did not receive HSTS header
 expressfinance.co.za: did not receive HSTS header
 extreemhost.nl: did not receive HSTS header
 extremenetworking.net: could not connect to host
 exy.pw: could not connect to host
 eyeglassuniverse.com: did not receive HSTS header
 ez.fi: could not connect to host
@@ -1390,20 +1391,22 @@ fakeletters.org: did not receive HSTS he
 faktura.pl: did not receive HSTS header
 falconfrag.com: could not connect to host
 falkena.net: max-age too low: 5184000
 falkp.no: did not receive HSTS header
 fallenangelspirits.uk: could not connect to host
 familie-sprink.de: could not connect to host
 familie-zimmermann.at: could not connect to host
 familjenm.se: could not connect to host
+fantopia.club: could not connect to host
 fanyl.cn: could not connect to host
 farhadexchange.com: did not receive HSTS header
 fashioncare.cz: did not receive HSTS header
 fasset.jp: could not connect to host
+fastconfirm.com: could not connect to host
 fastograph.com: could not connect to host
 fastopen.ml: could not connect to host
 fatgeekflix.net: could not connect to host
 fatherhood.gov: did not receive HSTS header
 fatlossguide.xyz: could not connect to host
 fatox.de: could not connect to host
 fayolle.info: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 fbox.li: could not connect to host
@@ -1420,17 +1423,16 @@ feragon.net: did not receive HSTS header
 fernseher-kauf.de: could not connect to host
 ferrolatino.com: could not connect to host
 festember.com: did not receive HSTS header
 festrip.com: could not connect to host
 fexmen.com: could not connect to host
 ffmradio.de: did not receive HSTS header
 fhdhelp.de: could not connect to host
 fhdhilft.de: could not connect to host
-fierman.net: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 fifieldtech.com: could not connect to host
 fiftyshadesofluca.ml: could not connect to host
 fig.co: did not receive HSTS header
 fightr.co: could not connect to host
 fikt.space: could not connect to host
 filmipop.com: max-age too low: 0
 finalgear.com: did not receive HSTS header
 financieringsportaal.nl: did not receive HSTS header
@@ -1504,16 +1506,17 @@ foxdev.io: could not connect to host
 foxelbox.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 foxley-farm.co.uk: did not receive HSTS header
 foxley-seeds.co.uk: did not receive HSTS header
 foxleyseeds.co.uk: could not connect to host
 foxtrot.pw: could not connect to host
 fr33d0m.link: could not connect to host
 francevpn.xyz: could not connect to host
 frangor.info: did not receive HSTS header
+frankwei.xyz: could not connect to host
 franta.biz: did not receive HSTS header
 franta.email: did not receive HSTS header
 franzt.de: could not connect to host
 franzt.ovh: could not connect to host
 frasys.io: max-age too low: 7776000
 fredvoyage.fr: did not receive HSTS header
 freeflow.tv: could not connect to host
 freematthale.net: did not receive HSTS header
@@ -1539,17 +1542,16 @@ frusky.de: did not receive HSTS header
 frusky.net: could not connect to host
 fspphoto.com: could not connect to host
 ftctele.com: did not receive HSTS header
 fuckbilibili.com: did not receive HSTS header
 fuckgfw233.org: could not connect to host
 fukushima-web.com: did not receive HSTS header
 fundacionhijosdelsol.org: could not connect to host
 funkyweddingideas.com.au: could not connect to host
-funnyang.com: could not connect to host
 funrun.com: did not receive HSTS header
 furiffic.com: did not receive HSTS header
 furnation.com: could not connect to host
 furry.be: max-age too low: 86400
 fusionmate.com: could not connect to host
 futbol11.com: did not receive HSTS header
 futurenda.com: could not connect to host
 futuretechnologi.es: could not connect to host
@@ -1687,33 +1689,32 @@ goerner.me: did not receive HSTS header
 goge.site: could not connect to host
 gogenenglish.com: could not connect to host
 gogetssl.com: did not receive HSTS header
 goggs.eu: did not receive HSTS header
 gogold-g.com: could not connect to host
 gold24.in: did not receive HSTS header
 goldendata.io: could not connect to host
 golocal-media.de: did not receive HSTS header
-gonzalosanchez.mx: could not connect to host
+gonzalosanchez.mx: did not receive HSTS header
 goodenough.nz: did not receive HSTS header
 goodwin43.ru: could not connect to host
 google: could not connect to host (error ignored - included regardless)
 googlemail.com: did not receive HSTS header (error ignored - included regardless)
 googleplex.com: did not receive HSTS header (error ignored - included regardless)
 goolok.com: could not connect to host
 gorilla-gym.site: could not connect to host
 goto.google.com: did not receive HSTS header (error ignored - included regardless)
 gotowned.org: did not receive HSTS header
 gotspot.com: could not connect to host
 gottcode.org: did not receive HSTS header
 gov.ax: could not connect to host
 govillemo.ca: did not receive HSTS header
 gozel.com.tr: did not receive HSTS header
 gparent.org: did not receive HSTS header
-gpfclan.de: could not connect to host
 gpsfix.cz: could not connect to host
 gpstuner.com: did not receive HSTS header
 gracesofgrief.com: max-age too low: 86400
 gradienthosting.co.uk: did not receive HSTS header
 graffen.dk: did not receive HSTS header
 grandmascookieblog.com: did not receive HSTS header
 grantedby.me: could not connect to host
 graph.no: did not receive HSTS header
@@ -1744,46 +1745,44 @@ gsm-map.com: could not connect to host
 gsnort.com: did not receive HSTS header
 gtamodshop.org: could not connect to host
 gtanda.tk: could not connect to host
 gtlfsonlinepay.com: did not receive HSTS header
 gtraxapp.com: could not connect to host
 gts-schulsoftware.de: did not receive HSTS header
 guava.studio: did not receive HSTS header
 guilde-vindicta.fr: did not receive HSTS header
-guildgearscore.cf: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 gulenet.com: could not connect to host
 gunnarhafdal.com: did not receive HSTS header
 gurom.lv: could not connect to host
 gurusupe.com: could not connect to host
 guso.gq: could not connect to host
-guso.ml: could not connect to host
 guso.site: could not connect to host
 guso.tech: could not connect to host
 gussi.is: did not receive HSTS header
 gvt2.com: could not connect to host (error ignored - included regardless)
 gvt3.com: could not connect to host (error ignored - included regardless)
 gw2reload.eu: could not connect to host
 gwijaya.com: could not connect to host
 gwtest.us: could not connect to host
 gxlrx.net: could not connect to host
 gyboche.com: could not connect to host
 gyboche.science: could not connect to host
 gycis.me: could not connect to host
 gypthecat.com: max-age too low: 604800
 gyz.io: could not connect to host
-gzitech.com: could not connect to host
 h2check.org: could not connect to host
 haarkliniek.com: did not receive HSTS header
 habanaavenue.com: did not receive HSTS header
 habbo.life: did not receive HSTS header
 hablemosdetecnologia.com.ve: could not connect to host
 hack.cz: could not connect to host
 hack.li: did not receive HSTS header
 hacker.one: could not connect to host
+hackerchai.com: could not connect to host
 hackerforever.com: did not receive HSTS header
 hackerone-ext-adroll.com: could not connect to host
 hackest.org: did not receive HSTS header
 hackit.im: could not connect to host
 hadzic.co: could not connect to host
 haeckdesign.com: did not receive HSTS header
 hahayidu.org: could not connect to host
 haitschi.com: could not connect to host
@@ -1801,21 +1800,19 @@ hanimalis.fr: could not connect to host
 hansen.hn: could not connect to host
 hao2taiwan.com: max-age too low: 0
 haoyugao.com: could not connect to host
 hapissl.com: could not connect to host
 happyfabric.me: did not receive HSTS header
 happygastro.com: could not connect to host
 harabuhouse.com: did not receive HSTS header
 harbor-light.net: could not connect to host
-hardfalcon.net: could not connect to host
 hardline.xyz: could not connect to host
 haribosupermix.com: could not connect to host
 harmonycosmetic.com: max-age too low: 300
-harrisonsand.com: could not connect to host
 harristony.com: could not connect to host
 hartmancpa.com: did not receive HSTS header
 harvestrenewal.org: did not receive HSTS header
 harz.cloud: could not connect to host
 has.vision: could not connect to host
 hash-list.com: could not connect to host
 hasilocke.de: did not receive HSTS header
 haste.ch: could not connect to host
@@ -1891,16 +1888,17 @@ horosho.in: could not connect to host
 horseboners.xxx: did not receive HSTS header
 hortifarm.ro: did not receive HSTS header
 horvathtom.com: could not connect to host
 hosteasy.nl: did not receive HSTS header
 hosted-service.com: did not receive HSTS header
 hostedtalkgadget.google.com: did not receive HSTS header (error ignored - included regardless)
 hostgarou.com: did not receive HSTS header
 hostinaus.com.au: could not connect to host
+hostinghelp.guru: could not connect to host
 hostisan.com: did not receive HSTS header
 hotchillibox.com: max-age too low: 0
 hotchoc.io: did not receive HSTS header
 houkago-step.com: did not receive HSTS header
 housemaadiah.org: did not receive HSTS header
 housingstudents.org.uk: could not connect to host
 howrandom.org: could not connect to host
 howtocuremysciatica.com: could not connect to host
@@ -1915,17 +1913,16 @@ hu.search.yahoo.com: did not receive HST
 huarongdao.com: max-age too low: 1
 huffduffer.com: could not connect to host
 hugocollignon.fr: could not connect to host
 hugosleep.com.au: did not receive HSTS header
 humblefinances.com: could not connect to host
 humeurs.net: could not connect to host
 humpteedumptee.in: did not receive HSTS header
 huntshomeinspections.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
-hupp.se: could not connect to host
 hurricanelabs.com: did not receive HSTS header
 huskybutt.dog: could not connect to host
 hydra.ws: could not connect to host
 hydronium.cf: could not connect to host
 hydronium.ga: could not connect to host
 hydronium.me: could not connect to host
 hydronium.tk: could not connect to host
 hyper69.com: did not receive HSTS header
@@ -1965,17 +1962,16 @@ ifleurs.com: could not connect to host
 ifx.ee: could not connect to host
 ignatisd.gr: did not receive HSTS header
 igule.net: could not connect to host
 ihrlotto.de: could not connect to host
 ihrnationalrat.ch: could not connect to host
 ihsbsd.me: could not connect to host
 ihsbsd.tk: could not connect to host
 ihuanmeng.com: did not receive HSTS header
-ikkatsu-satei.jp: did not receive HSTS header
 ikujii.com: max-age too low: 0
 ikwilguidobellen.nl: did not receive HSTS header
 ilbuongiorno.it: did not receive HSTS header
 ilikerainbows.co: could not connect to host
 ilikerainbows.co.uk: could not connect to host
 ilmconpm.de: did not receive HSTS header
 ilona.graphics: max-age too low: 3600
 iluvscotland.co.uk: did not receive HSTS header
@@ -2020,24 +2016,22 @@ inkable.com.au: did not receive HSTS hea
 inked-guy.de: did not receive HSTS header
 inkedguy.de: could not connect to host
 inkstory.gr: did not receive HSTS header
 inksupply.com: did not receive HSTS header
 inleaked.com: could not connect to host
 inmyarea.com: max-age too low: 0
 innophate-security.nl: could not connect to host
 ins1gn1a.com: did not receive HSTS header
-insane-bullets.com: could not connect to host
 insane.zone: could not connect to host
 insite-feedback.com: did not receive HSTS header
 inspire-av.com: did not receive HSTS header
 inspiroinc.com: could not connect to host
 instacart.com: did not receive HSTS header
 instantdev.io: could not connect to host
-instela.com: did not receive HSTS header
 institutoflordelavida.com: could not connect to host
 intel.li: could not connect to host
 intelldynamics.com: could not connect to host
 interference.io: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 interlun.com: could not connect to host
 internetcasinos.de: could not connect to host
 internetcensus.org: could not connect to host
 interserved.com: did not receive HSTS header
@@ -2046,17 +2040,17 @@ intim-uslugi-kazan.net: could not connec
 intimtoy.com.ua: could not connect to host
 intrp.net: did not receive HSTS header
 inverselink-user-content.com: could not connect to host
 inverselink.com: could not connect to host
 invite24.pro: could not connect to host
 inwesttitle.com: max-age too low: 0
 ionx.co.uk: did not receive HSTS header
 iop.intuit.com: max-age too low: 86400
-iosmods.com: could not connect to host
+iosmods.com: did not receive HSTS header
 iostips.ru: could not connect to host
 iotsms.io: could not connect to host
 ip6.im: did not receive HSTS header
 ipmimagazine.com: did not receive HSTS header
 iprody.com: could not connect to host
 iptel.by: max-age too low: 0
 iptel.ro: could not connect to host
 ipv6cloud.club: could not connect to host
@@ -2128,17 +2122,17 @@ japlex.com: could not connect to host
 jaqen.ch: could not connect to host
 jardins-utopie.net: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 jaredeberle.org: did not receive HSTS header
 jaroslavtrsek.cz: did not receive HSTS header
 jartza.org: could not connect to host
 jasmineconseil.com: could not connect to host
 jasonrobinson.me: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 jasonroe.me: did not receive HSTS header
-jasonsansone.com: could not connect to host
+jasonsansone.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 jastoria.pl: could not connect to host
 jayblock.com: did not receive HSTS header
 jayschulman.com: did not receive HSTS header
 jayscoaching.com: did not receive HSTS header
 jayshao.com: did not receive HSTS header
 jazzinutrecht.info: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 jazzncheese.com: could not connect to host
 jbn.mx: could not connect to host
@@ -2186,17 +2180,16 @@ johnrom.com: did not receive HSTS header
 jonas-keidel.de: did not receive HSTS header
 jonasgroth.se: did not receive HSTS header
 jonathan.ir: could not connect to host
 jonathancarter.org: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 jonn.me: could not connect to host
 joostbovee.nl: did not receive HSTS header
 jordanhamilton.me: could not connect to host
 joretapo.fr: did not receive HSTS header
-jornadasciberdefensa2016.es: did not receive HSTS header
 josahrens.me: could not connect to host
 joshi.su: could not connect to host
 joshstroup.me: could not connect to host
 jottit.com: could not connect to host
 jpbike.cz: could not connect to host
 jrc9.ca: did not receive HSTS header
 jrgold.me: could not connect to host
 jrmd.io: could not connect to host
@@ -2208,33 +2201,33 @@ jualautoclave.com: did not receive HSTS 
 jualssh.com: could not connect to host
 juliamweber.de: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 julian-kipka.de: could not connect to host
 jumbox.xyz: could not connect to host
 junaos.xyz: did not receive HSTS header
 junge-selbsthilfe.info: could not connect to host
 junqtion.com: could not connect to host
 jupp0r.de: did not receive HSTS header
-justanothercompany.name: could not connect to host
 justlikethat.hosting: did not receive HSTS header
 justnaw.co.uk: could not connect to host
 justudin.com: did not receive HSTS header
 juwairen.cn: did not receive HSTS header
 jvoice.net: could not connect to host
 jwilsson.me: could not connect to host
 jxm.in: could not connect to host
 jznet.org: max-age too low: 86400
 k-dev.de: could not connect to host
 ka-clan.com: could not connect to host
 kabuabc.com: did not receive HSTS header
 kadioglumakina.com.tr: did not receive HSTS header
 kaela.design: could not connect to host
 kahopoon.net: could not connect to host
 kaisers.de: did not receive HSTS header
 kalami.nl: did not receive HSTS header
+kaleidomarketing.com: could not connect to host
 kamikano.com: could not connect to host
 kaneo-gmbh.de: did not receive HSTS header
 kaplatz.is: could not connect to host
 kapucini.si: max-age too low: 0
 karaoketonight.com: could not connect to host
 kasilag.me: did not receive HSTS header
 katiaetdavid.fr: could not connect to host
 katproxy.online: could not connect to host
@@ -2327,24 +2320,22 @@ kostya.net: could not connect to host
 kotonehoko.net: could not connect to host
 kotovstyle.ru: could not connect to host
 kr.search.yahoo.com: did not receive HSTS header
 kramsj.uk: could not connect to host
 krayx.com: could not connect to host
 kreavis.com: did not receive HSTS header
 kredite.sale: could not connect to host
 kriegt.es: could not connect to host
-krmela.com: could not connect to host
 kroetenfuchs.de: could not connect to host
 kropkait.pl: could not connect to host
 krouzkyliduska.cz: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 krunut.com: did not receive HSTS header
 krypteia.org: could not connect to host
 kryptomech.com: could not connect to host
-kschv-rdeck.de: did not receive HSTS header
 ksfh-mail.de: could not connect to host
 kstan.me: could not connect to host
 kswriter.com: could not connect to host
 kucom.it: did not receive HSTS header
 kueulangtahunanak.net: could not connect to host
 kummerlaender.eu: did not receive HSTS header
 kupelne-ptacek.sk: did not receive HSTS header
 kuppingercole.com: did not receive HSTS header
@@ -2446,17 +2437,16 @@ lianye3.cc: could not connect to host
 lianye4.cc: could not connect to host
 lianye5.cc: could not connect to host
 lianye6.cc: could not connect to host
 lianyexiuchang.in: could not connect to host
 liaoshuma.com: could not connect to host
 libertyrp.org: could not connect to host
 library.linode.com: did not receive HSTS header
 librechan.net: could not connect to host
-libscode.com: could not connect to host
 lidl-selection.at: could not connect to host
 lidow.eu: could not connect to host
 lifeguard.aecom.com: did not receive HSTS header
 lifeinitsownway.com: did not receive HSTS header
 lifeskillsdirect.com: did not receive HSTS header
 lifestylehunter.co.uk: did not receive HSTS header
 lifetimemoneymachine.com: did not receive HSTS header
 lifi.digital: did not receive HSTS header
@@ -2562,20 +2552,20 @@ m.nu: did not receive HSTS header
 m2epro.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 m2tc.fr: could not connect to host
 m3-gmbh.de: did not receive HSTS header
 m82labs.com: did not receive HSTS header
 maarten.nyc: did not receive HSTS header
 maartenvandekamp.nl: did not receive HSTS header
 mac-torrents.me: did not receive HSTS header
 macchaberrycream.com: could not connect to host
-macchedil.com: did not receive HSTS header
 macdj.tk: could not connect to host
 macgeneral.de: did not receive HSTS header
 machon.biz: could not connect to host
+macosxfilerecovery.com: did not receive HSTS header
 madars.org: did not receive HSTS header
 maddin.ga: could not connect to host
 madebymagnitude.com: did not receive HSTS header
 maderwin.com: could not connect to host
 mae-berlinistanbul.com: could not connect to host
 mafamane.com: could not connect to host
 maff.scot: did not receive HSTS header
 mafiareturns.com: max-age too low: 2592000
@@ -2610,19 +2600,19 @@ marcush.de: did not receive HSTS header
 marcuskoh.com: did not receive HSTS header
 mariannematthew.com: could not connect to host
 marie-curie.fr: could not connect to host
 marie-elisabeth.dk: did not receive HSTS header
 mario.party: did not receive HSTS header
 markaconnor.com: could not connect to host
 markayapilandirma.com: could not connect to host
 market.android.com: did not receive HSTS header (error ignored - included regardless)
-markprof.ru: could not connect to host
 markrego.com: could not connect to host
 marktboten.de: did not receive HSTS header
+marktissink.nl: did not receive HSTS header
 markus-dev.com: did not receive HSTS header
 markusweimar.de: did not receive HSTS header
 marleyresort.com: did not receive HSTS header
 marshut.net: could not connect to host
 martiert.com: could not connect to host
 martijnvhoof.nl: could not connect to host
 martineve.com: did not receive HSTS header
 martinsfamilyappliance.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
@@ -2653,17 +2643,16 @@ mavisang.cf: could not connect to host
 mawe.red: could not connect to host
 maya.mg: could not connect to host
 mca2017.org: did not receive HSTS header
 mcc.re: could not connect to host
 mccarty.io: could not connect to host
 mccrackon.com: could not connect to host
 mcdonalds.ru: did not receive HSTS header
 mcga.media: did not receive HSTS header
-mcjackk77.com: could not connect to host
 mclab.su: could not connect to host
 mdewendt.de: could not connect to host
 mdfnet.se: did not receive HSTS header
 mdscomp.net: did not receive HSTS header
 mea.in.ua: could not connect to host
 meamod.com: did not receive HSTS header
 mechanus.io: max-age too low: 2592000
 medallia.io: could not connect to host
@@ -2781,17 +2770,16 @@ mobilpass.no: could not connect to host
 mocloud.eu: could not connect to host
 model9.io: did not receive HSTS header
 modemagazines.co.uk: could not connect to host
 modernibytovytextil.cz: could not connect to host
 moebel-nagel.de: did not receive HSTS header
 moelord.org: could not connect to host
 moen.io: did not receive HSTS header
 mogry.net: did not receive HSTS header
-moho.kr: did not receive HSTS header
 monarca.systems: could not connect to host
 monasterialis.eu: could not connect to host
 mondar.io: did not receive HSTS header
 mondopoint.com: did not receive HSTS header
 moneytoday.com: max-age too low: 0
 monitman.com: could not connect to host
 montenero.pl: could not connect to host
 moon.lc: could not connect to host
@@ -2814,17 +2802,16 @@ motoryz.com: max-age too low: 300
 mottvd.com: could not connect to host
 moula.com.au: did not receive HSTS header
 mountainmusicpromotions.com: did not receive HSTS header
 movepin.com: did not receive HSTS header
 moviesabout.net: could not connect to host
 moy-gorod.od.ua: did not receive HSTS header
 moy.cat: did not receive HSTS header
 mp3juices.is: could not connect to host
-mpintaamalabanna.it: could not connect to host
 mqas.net: could not connect to host
 mrdani.net: could not connect to host
 mrettich.org: did not receive HSTS header
 mrnonz.com: max-age too low: 0
 mrpopat.in: did not receive HSTS header
 mrs-shop.com: did not receive HSTS header
 msc-seereisen.net: could not connect to host
 msno.no: did not receive HSTS header
@@ -2859,56 +2846,54 @@ myairshop.gr: could not connect to host
 myandroidtools.cc: could not connect to host
 mybon.at: could not connect to host
 mybudget.xyz: could not connect to host
 mybuilderinlondon.co.uk: could not connect to host
 mycollab.net: could not connect to host
 mycoted.com: did not receive HSTS header
 mydeos.com: could not connect to host
 mydigipass.com: did not receive HSTS header
-myg21.com: max-age too low: 0
 mygate.at: could not connect to host
 mygdut.com: did not receive HSTS header
 mygov.scot: did not receive HSTS header
 myiocc.org: could not connect to host
 mykolab.com: did not receive HSTS header
 mykreuzfahrt.de: could not connect to host
 myni.io: could not connect to host
 mypagella.com: could not connect to host
 mypagella.eu: could not connect to host
 mypagella.it: could not connect to host
 mypension.ca: could not connect to host
 myphonebox.de: could not connect to host
 myraytech.net: did not receive HSTS header
 mysecretrewards.com: did not receive HSTS header
 mystery-science-theater-3000.de: did not receive HSTS header
-mythslegendscollection.com: did not receive HSTS header
 myvirtualserver.com: max-age too low: 2592000
 myzone.com: did not receive HSTS header
+mziulu.me: could not connect to host
 n0psled.nl: could not connect to host
 n2x.in: could not connect to host
 n4l.pw: could not connect to host
 nabytko.cz: could not connect to host
 nadia.pt: could not connect to host
 nagoya-kyuyo.com: could not connect to host
 naiharngym.com: did not receive HSTS header
 najedlo.sk: did not receive HSTS header
 nakliyatsirketi.biz: did not receive HSTS header
 nakuro.de: could not connect to host
-nalifornia.com: did not receive HSTS header
+nalifornia.com: could not connect to host
 nallon.com.br: could not connect to host
 namacindia.com: did not receive HSTS header
 namaho.com: could not connect to host
 nametaken-cloud.duckdns.org: could not connect to host
 namorico.me: did not receive HSTS header
 nan.zone: could not connect to host
 nanogeneinc.com: could not connect to host
 nanto.eu: could not connect to host
 narada.com.ua: could not connect to host
-nargileh.nl: could not connect to host
 narindal.ch: did not receive HSTS header
 natalia-fadeeva.ru: could not connect to host
 natalia.io: could not connect to host
 natalt.org: did not receive HSTS header
 nathanmfarrugia.com: did not receive HSTS header
 natural-progesterone.net: did not receive HSTS header
 naturesystems.cz: max-age too low: 0
 natuurbehangnederland.nl: could not connect to host
@@ -2919,17 +2904,16 @@ navenlle.com: did not receive HSTS heade
 navjobs.com: did not receive HSTS header
 nbb.io: could not connect to host
 nbg-ha.de: could not connect to host
 ncc60205.info: could not connect to host
 ncpc.gov: could not connect to host
 nct.org.uk: max-age too low: 1
 nctx.co.uk: did not receive HSTS header
 near.st: did not receive HSTS header
-neel.ch: could not connect to host
 neels.ch: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 neftaly.com: did not receive HSTS header
 neilgreen.net: did not receive HSTS header
 neko-life.com: did not receive HSTS header
 neko-system.com: did not receive HSTS header
 nemno.de: could not connect to host
 nemovement.org: could not connect to host
 neonisi.com: could not connect to host
@@ -2973,20 +2957,19 @@ nicky.io: did not receive HSTS header
 nicoborghuis.nl: could not connect to host
 nicolasbettag.me: did not receive HSTS header
 niconiconi.xyz: could not connect to host
 niconode.com: could not connect to host
 nien.chat: could not connect to host
 nightwinds.tk: could not connect to host
 nightx.uk: could not connect to host
 niho.jp: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
-niklas.pw: could not connect to host
 nikomo.fi: could not connect to host
 ninchisho-online.com: did not receive HSTS header
-ninhs.org: did not receive HSTS header
+ninhs.org: could not connect to host
 nippler.org: did not receive HSTS header
 nippombashi.net: did not receive HSTS header
 nipponcareers.com: did not receive HSTS header
 nixien.fr: could not connect to host
 nkinka.de: did not receive HSTS header
 nlegall.fr: did not receive HSTS header
 nmctest.net: could not connect to host
 nnya.cat: could not connect to host
@@ -3017,28 +3000,30 @@ nouvelle-vague-saint-cast.fr: did not re
 novacoast.com: did not receive HSTS header
 novatrucking.de: could not connect to host
 nowak.ninja: did not receive HSTS header
 noworrywp.com: could not connect to host
 nozoe.jp: did not receive HSTS header
 np.search.yahoo.com: did not receive HSTS header
 npol.de: could not connect to host
 nqesh.com: could not connect to host
+nrizzio.me: could not connect to host
 ntbs.pro: could not connect to host
 ntse.xyz: could not connect to host
 nu3.at: did not receive HSTS header
 nu3.ch: did not receive HSTS header
 nu3.co.uk: did not receive HSTS header
 nu3.com: did not receive HSTS header
 nu3.de: did not receive HSTS header
 nu3.dk: did not receive HSTS header
 nu3.fi: did not receive HSTS header
 nu3.fr: did not receive HSTS header
 nu3.no: did not receive HSTS header
 nu3.se: did not receive HSTS header
+nubella.com.au: did not receive HSTS header
 nufla.de: could not connect to host
 null-sec.ru: could not connect to host
 null.cat: could not connect to host
 null.tips: could not connect to host
 nullpoint.at: did not receive HSTS header
 number.me: did not receive HSTS header
 numericacu.com: did not receive HSTS header
 numero-di-telefono.it: could not connect to host
@@ -3338,26 +3323,27 @@ pocketsix.com: did not receive HSTS head
 pocloud.homelinux.net: could not connect to host
 poiema.com.sg: did not receive HSTS header
 pol.in.th: could not connect to host
 pole.net.nz: could not connect to host
 poleartschool.com: could not connect to host
 policeiwitness.sg: could not connect to host
 polimat.org: could not connect to host
 politically-incorrect.xyz: could not connect to host
-politologos.org: could not connect to host
+politologos.org: did not receive HSTS header
 polycoise.com: could not connect to host
 polypho.nyc: could not connect to host
 pompompoes.com: could not connect to host
 pontualcomp.com: max-age too low: 2592000
 poolsandstuff.com: did not receive HSTS header
 poon.tech: could not connect to host
 portalplatform.net: did not receive HSTS header
 poshpak.com: max-age too low: 86400
 postcodewise.co.uk: did not receive HSTS header
+posterspy.com: did not receive HSTS header
 postscheduler.org: could not connect to host
 posylka.de: did not receive HSTS header
 poussinooz.fr: could not connect to host
 povitria.net: could not connect to host
 power99press.com: did not receive HSTS header
 powerplannerapp.com: did not receive HSTS header
 powerxequality.com: could not connect to host
 ppr-truby.ru: could not connect to host
@@ -3456,28 +3442,28 @@ qwilink.me: did not receive HSTS header
 r10n.com: did not receive HSTS header
 r15.me: could not connect to host
 r3bl.me: did not receive HSTS header
 ra-schaal.de: could not connect to host
 raajheshkannaa.com: could not connect to host
 radicaleducation.net: could not connect to host
 rafaelcz.de: could not connect to host
 railgun.com.cn: could not connect to host
+railjob.cn: could not connect to host
 rainbowbarracuda.com: could not connect to host
 ramonj.nl: could not connect to host
 randomcage.com: did not receive HSTS header
 randomcloud.net: could not connect to host
 randomhero.cloud: could not connect to host
 rankthespot.com: could not connect to host
 rannseier.org: did not receive HSTS header
 rapido.nu: did not receive HSTS header
 rapidresearch.me: could not connect to host
 rapidthunder.io: could not connect to host
 rasing.me: did not receive HSTS header
-raspass.me: could not connect to host
 rastreador.com.es: did not receive HSTS header
 ratajczak.fr: could not connect to host
 rate-esport.de: could not connect to host
 rationalism.com: could not connect to host
 raulfraile.net: could not connect to host
 raven.lipetsk.ru: could not connect to host
 rawet.se: did not receive HSTS header
 rawstorieslondon.com: could not connect to host
@@ -3534,17 +3520,16 @@ res-rheingau.de: did not receive HSTS he
 res42.com: could not connect to host
 research.facebook.com: did not receive HSTS header
 reserve-online.net: did not receive HSTS header
 respice.xyz: could not connect to host
 respostas.com.br: did not receive HSTS header
 restchart.com: did not receive HSTS header
 retcor.net: could not connect to host
 retrotracks.net: max-age too low: 0
-reulitz.de: could not connect to host
 revealdata.com: did not receive HSTS header
 revello.org: did not receive HSTS header
 reverie.pw: could not connect to host
 reviews.anime.my: max-age too low: 5184000
 revtut.net: did not receive HSTS header
 rewardstock.com: max-age too low: 0
 rex.st: could not connect to host
 rhapsodhy.hu: could not connect to host
@@ -3576,17 +3561,16 @@ rngmeme.com: could not connect to host
 roadfeast.com: could not connect to host
 roan24.pl: did not receive HSTS header
 robertglastra.com: could not connect to host
 robigalia.org: did not receive HSTS header
 robteix.com: did not receive HSTS header
 robtex.net: did not receive HSTS header
 robtex.org: did not receive HSTS header
 rochman.id: could not connect to host
-rocketr.net: did not receive HSTS header
 rocksberg.net: could not connect to host
 rockstarloan.com: max-age too low: 0
 roddis.net: did not receive HSTS header
 rodney.id.au: did not receive HSTS header
 rodosto.com: did not receive HSTS header
 roeper.party: could not connect to host
 roesemann.email: could not connect to host
 roguelikecenter.fr: did not receive HSTS header
@@ -3605,16 +3589,17 @@ rossen.be: did not receive HSTS header
 rotterdamjazz.info: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 roundtheme.com: did not receive HSTS header
 rous.se: could not connect to host
 rout0r.org: did not receive HSTS header
 rouvray.org: could not connect to host
 royalpub.net: did not receive HSTS header
 rr.in.th: could not connect to host
 rrke.cc: did not receive HSTS header
+rrom.me: could not connect to host
 rsajeey.info: could not connect to host
 rsauget.fr: could not connect to host
 rsf.io: could not connect to host
 rsmaps.org: could not connect to host
 rubbereggs.ca: could not connect to host
 rubberfurs.org: max-age too low: 86400
 rubecodeberg.com: could not connect to host
 rubenschulz.nl: did not receive HSTS header
@@ -3634,17 +3619,16 @@ russmarshall.com: could not connect to h
 ruxit.com: did not receive HSTS header
 rw.search.yahoo.com: did not receive HSTS header
 rx-contact.com: did not receive HSTS header
 rxprep.com: did not receive HSTS header
 rxv.cc: could not connect to host
 ryansmithphotography.com: did not receive HSTS header
 ryanteck.uk: did not receive HSTS header
 s.how: did not receive HSTS header
-s007.co: could not connect to host
 safematix.com: could not connect to host
 safewings-nh.nl: did not receive HSTS header
 safic.net: could not connect to host
 sageth.com: max-age too low: 0
 sah3.net: could not connect to host
 sairai.bid: did not receive HSTS header
 sakaki.anime.my: max-age too low: 5184000
 sakaserver.com: did not receive HSTS header
@@ -3657,17 +3641,17 @@ saml2.com: could not connect to host
 sampoznay.ru: did not receive HSTS header
 samraskauskas.com: could not connect to host
 samsen.club: did not receive HSTS header
 sanasalud.org: could not connect to host
 sandrolittke.de: did not receive HSTS header
 sandviks.com: did not receive HSTS header
 sangwon.org: could not connect to host
 sansemea.com: did not receive HSTS header
-sansonehowell.com: could not connect to host
+sansonehowell.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 sarah-beckett-harpist.com: did not receive HSTS header
 sarahsweetlife.com: could not connect to host
 sarakas.com: could not connect to host
 sarisonproductions.com: did not receive HSTS header
 saruwebshop.co.za: could not connect to host
 sash.pw: could not connect to host
 sat.rent: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 satinn.pl: did not receive HSTS header
@@ -3684,16 +3668,17 @@ saunasandstuff.com: did not receive HSTS
 savannahtasteexperience.com: did not receive HSTS header
 saveaward.gov: could not connect to host
 saveyour.biz: did not receive HSTS header
 sawamura-rental.com: did not receive HSTS header
 sazima.ru: did not receive HSTS header
 sbox-archives.com: could not connect to host
 sby.de: did not receive HSTS header
 sc4le.com: could not connect to host
+scannabi.com: could not connect to host
 scepticism.com: could not connect to host
 schadegarant.net: could not connect to host
 schnell-gold.com: could not connect to host
 schoop.me: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 schrauger.com: did not receive HSTS header
 schrauger.info: did not receive HSTS header
 schrauger.net: did not receive HSTS header
 schrauger.org: did not receive HSTS header
@@ -3760,16 +3745,17 @@ semps.de: did not receive HSTS header
 senedirect.com: did not receive HSTS header
 sensiblemn.org: could not connect to host
 sensibus.com: did not receive HSTS header
 seo.consulting: did not receive HSTS header
 seomobo.com: could not connect to host
 seowarp.net: did not receive HSTS header
 sep23.ru: did not receive HSTS header
 seq.tf: did not receive HSTS header
+serathius.ovh: could not connect to host
 serenitycreams.com: did not receive HSTS header
 serfdom.io: did not receive HSTS header
 serized.pw: could not connect to host
 servercode.ca: did not receive HSTS header
 serverdensity.io: did not receive HSTS header
 servergno.me: did not receive HSTS header
 servermonkey.nl: could not connect to host
 seryo.moe: could not connect to host
@@ -3778,36 +3764,36 @@ sethcaplan.com: could not connect to hos
 setphaserstostun.org: could not connect to host
 settleapp.co: could not connect to host
 setuid.de: could not connect to host
 setuid.io: did not receive HSTS header
 setuid0.kr: could not connect to host
 sexpay.net: could not connect to host
 seyahatsagliksigortalari.com: could not connect to host
 sfsltd.com: did not receive HSTS header
+sh-network.de: could not connect to host
 shadoom.com: did not receive HSTS header
 shadowmorph.info: did not receive HSTS header
 shadowsocks.net: could not connect to host
 shakepeers.org: did not receive HSTS header
 shanesage.com: could not connect to host
-shanewadleigh.com: could not connect to host
 shareimg.xyz: could not connect to host
 sharepass.pw: could not connect to host
 shauncrowley.co.uk: could not connect to host
 shaunwheelhou.se: could not connect to host
 shawnh.net: could not connect to host
 shellsec.pw: did not receive HSTS header
 shereallyheals.com: could not connect to host
 shibe.club: could not connect to host
 shiftins.com: did not receive HSTS header
 shiinko.com: could not connect to host
 shinebijoux.com.br: could not connect to host
 shinju.moe: could not connect to host
 shinonome-lab.eu.org: could not connect to host
-shiona.xyz: could not connect to host
+shiona.xyz: did not receive HSTS header
 shocksrv.com: did not receive HSTS header
 shooshosha.com: did not receive HSTS header
 shopontarget.com: did not receive HSTS header
 shoprose.ru: could not connect to host
 shops.neonisi.com: could not connect to host
 shortr.li: could not connect to host
 showkeeper.tv: did not receive HSTS header
 shukatsu-note.com: could not connect to host
@@ -3845,17 +3831,16 @@ sinful.pw: could not connect to host
 singul4rity.com: could not connect to host
 siraweb.org: did not receive HSTS header
 siriad.com: did not receive HSTS header
 sirius-lee.net: could not connect to host
 sitennisclub.com: did not receive HSTS header
 siterip.org: could not connect to host
 sites.google.com: did not receive HSTS header (error ignored - included regardless)
 sitesten.com: did not receive HSTS header
-sitsy.ru: did not receive HSTS header
 sixtwentyten.com: did not receive HSTS header
 skhosting.eu: did not receive HSTS header
 skile.ru: could not connect to host
 skk.io: could not connect to host
 skoda-clever-lead.de: could not connect to host
 skoda-im-dialog.de: could not connect to host
 skotty.io: did not receive HSTS header
 skullhouse.nyc: did not receive HSTS header
@@ -3866,16 +3851,17 @@ slashand.co: did not receive HSTS header
 slashem.me: did not receive HSTS header
 slattery.co: could not connect to host
 sleep10.com: could not connect to host
 slicketl.com: did not receive HSTS header
 slightfuture.click: could not connect to host
 slix.io: could not connect to host
 slope.haus: could not connect to host
 slovakiana.sk: did not receive HSTS header
+slowfood.es: could not connect to host
 sluitkampzeist.nl: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 slycurity.de: could not connect to host
 smart-mirror.de: did not receive HSTS header
 smart-ov.nl: could not connect to host
 smartcoin.com.br: could not connect to host
 smartlend.se: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 smartofficesandsmarthomes.com: did not receive HSTS header
 smartrak.co.nz: did not receive HSTS header
@@ -3888,17 +3874,16 @@ smkn1lengkong.sch.id: did not receive HS
 smksi2.com: could not connect to host
 smove.sg: did not receive HSTS header
 smusg.com: did not receive HSTS header
 snailing.org: could not connect to host
 snakehosting.dk: did not receive HSTS header
 snapappointments.com: did not receive HSTS header
 snapappts.com: could not connect to host
 snapworks.net: did not receive HSTS header
-sneberger.cz: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 snel4u.nl: could not connect to host
 snelwerk.be: could not connect to host
 sng.my: could not connect to host
 snille.com: could not connect to host
 snip.host: could not connect to host
 snoozedds.com: max-age too low: 600
 snoqualmiefiber.org: did not receive HSTS header
 sobabox.ru: could not connect to host
@@ -3921,28 +3906,29 @@ solinter.com.br: did not receive HSTS he
 solit.systems: did not receive HSTS header
 soll-i.ch: did not receive HSTS header
 solsystems.ru: could not connect to host
 someshit.xyz: could not connect to host
 somethingnew.xyz: could not connect to host
 sonicrainboom.rocks: could not connect to host
 soobi.org: did not receive HSTS header
 soondy.com: did not receive HSTS header
-sotiran.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
+sotiran.com: did not receive HSTS header
 sotor.de: did not receive HSTS header
 soulema.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 soulfulglamour.uk: could not connect to host
 sourcelair.com: did not receive HSTS header
 southside-crew.club: could not connect to host
 southworcestershiregpservices.co.uk: could not connect to host
 souyar.de: could not connect to host
 souyar.net: could not connect to host
 souyar.us: could not connect to host
 sovereignshare.com: could not connect to host
 sown.dyndns.org: could not connect to host
+sowncloud.de: did not receive HSTS header
 spacehq.org: max-age too low: 0
 spaggel.nl: could not connect to host
 sparelib.com: max-age too low: 3650
 spark.team: could not connect to host
 sparkbase.cn: could not connect to host
 sparklingsparklers.com: did not receive HSTS header
 sparsa.army: could not connect to host
 spartantheatre.org: max-age too low: 172800
@@ -3981,17 +3967,16 @@ srevilak.net: did not receive HSTS heade
 srna.sk: could not connect to host
 srrr.ca: could not connect to host
 ss.wtf: could not connect to host
 ssl.panoramio.com: did not receive HSTS header
 ssl.rip: could not connect to host
 ssmato.me: could not connect to host
 ssnc.org: max-age too low: 300
 sss3s.com: did not receive HSTS header
-st-news.de: could not connect to host
 stabletoken.com: could not connect to host
 stadjerspasonline.nl: could not connect to host
 stahl.xyz: could not connect to host
 stalschermer.nl: could not connect to host
 stamonicatourandtravel.com: could not connect to host
 standardssuck.org: did not receive HSTS header
 standingmist.com: did not receive HSTS header
 stargatepartners.com: did not receive HSTS header
@@ -4028,16 +4013,18 @@ stocktrade.de: could not connect to host
 stoffe-monster.de: did not receive HSTS header
 stole-my.bike: could not connect to host
 stole-my.tv: could not connect to host
 stopwoodfin.org: could not connect to host
 storecove.com: did not receive HSTS header
 storefrontify.com: did not receive HSTS header
 stormhub.org: could not connect to host
 stpatricksguild.com: did not receive HSTS header
+stpip.com: could not connect to host
+stpip.net: could not connect to host
 stqry.com: did not receive HSTS header
 str0.at: did not receive HSTS header
 strasweb.fr: did not receive HSTS header
 streamingeverywhere.com: did not receive HSTS header
 streamingmagazin.de: could not connect to host
 streampanel.net: did not receive HSTS header
 streams.dyndns.org: could not connect to host
 strictlysudo.com: could not connect to host
@@ -4152,33 +4139,32 @@ tcdw.net: could not connect to host
 tcl.ath.cx: did not receive HSTS header
 tcomms.org: max-age too low: 0
 tcp.expert: did not receive HSTS header
 teachforcanada.ca: did not receive HSTS header
 team-teasers.com: could not connect to host
 teamsocial.co: did not receive HSTS header
 teamzeus.cz: could not connect to host
 tech55i.com: did not receive HSTS header
-techassist.io: could not connect to host
+techassist.io: did not receive HSTS header
 techelements.co: could not connect to host
 techhipster.net: could not connect to host
 techhub.ml: could not connect to host
 techllage.com: could not connect to host
 techloaner.com: could not connect to host
 techmatehq.com: could not connect to host
 technogroup.cz: did not receive HSTS header
 technosavvyport.com: did not receive HSTS header
 techpointed.com: could not connect to host
 techreview.link: could not connect to host
 tedb.us: could not connect to host
 tegelsensanitaironline.nl: did not receive HSTS header
 tekshrek.com: did not receive HSTS header
 telefonnummer.online: could not connect to host
 telefoonnummerinfo.nl: could not connect to host
-telling.xyz: could not connect to host
 temehu.com: did not receive HSTS header
 tempcraft.net: could not connect to host
 tendertool.nl: could not connect to host
 tenni.xyz: could not connect to host
 tensei-slime.com: did not receive HSTS header
 tensionup.com: could not connect to host
 teos.online: could not connect to host
 teriiphotography.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
@@ -4238,20 +4224,22 @@ themoderate.xyz: could not connect to ho
 theodorejones.info: could not connect to host
 thepartywarehouse.co.uk: did not receive HSTS header
 thepiratebay.al: could not connect to host
 thepiratebay.tech: could not connect to host
 therewill.be: could not connect to host
 theseed.io: could not connect to host
 thestack.xyz: could not connect to host
 thestagchorleywood.co.uk: did not receive HSTS header
+thetechnical.me: could not connect to host
 thetomharling.com: max-age too low: 86400
 theurbanyoga.com: did not receive HSTS header
 thevintagenews.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 thewebfellas.com: did not receive HSTS header
+theyosh.nl: could not connect to host
 thezonders.com: did not receive HSTS header
 thierfreund.de: could not connect to host
 thingies.site: could not connect to host
 thinkcoding.de: could not connect to host
 thinkcoding.org: could not connect to host
 thirdpartytrade.com: did not receive HSTS header
 thirty5.net: did not receive HSTS header
 thisisacompletetest.ga: could not connect to host
@@ -4273,17 +4261,16 @@ ticktock.today: did not receive HSTS hea
 tictactux.de: could not connect to host
 tidmore.us: could not connect to host
 tiensnet.com: did not receive HSTS header
 tightlineproductions.com: did not receive HSTS header
 tikutiku.pl: max-age too low: 0
 tildebot.com: could not connect to host
 tilkah.com.au: could not connect to host
 tillcraft.com: could not connect to host
-tillseasyscore.com: could not connect to host
 timbeilby.com: could not connect to host
 timbuktutimber.com: did not receive HSTS header
 timcamara.com: did not receive HSTS header
 time-river.xyz: could not connect to host
 timestamp.io: did not receive HSTS header
 timnash.co.uk: did not receive HSTS header
 timotrans.de: did not receive HSTS header
 timotrans.eu: did not receive HSTS header
@@ -4321,22 +4308,24 @@ todobazar.es: could not connect to host
 tollmanz.com: did not receive HSTS header
 tom.horse: did not receive HSTS header
 tomask.info: max-age too low: 86400
 tomeara.net: could not connect to host
 tomharling.co.uk: max-age too low: 86400
 tomharling.uk: max-age too low: 86400
 tomharris.tech: did not receive HSTS header
 tomlankhorst.nl: did not receive HSTS header
+tomli.blog: could not connect to host
 tommsy.com: did not receive HSTS header
 tommyads.com: could not connect to host
 tonburi.jp: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 tonyfantjr.com: could not connect to host
 tonyw.xyz: could not connect to host
 toomanypillows.com: could not connect to host
+toool.org: did not receive HSTS header
 top-stage.net: could not connect to host
 topbargains.com.au: did not receive HSTS header
 topdeskdev.net: could not connect to host
 topmarine.se: could not connect to host
 topnewstoday.org: could not connect to host
 topshelfguild.com: could not connect to host
 torahanytime.com: did not receive HSTS header
 tosecure.link: could not connect to host
@@ -4357,16 +4346,17 @@ translate.googleapis.com: did not receiv
 transportal.sk: did not receive HSTS header
 travelinsurance.co.nz: did not receive HSTS header
 treeby.net: could not connect to host
 trendberry.ru: could not connect to host
 trinityaffirmations.com: max-age too low: 0
 trinitycore.org: max-age too low: 2592000
 tripdelta.com: did not receive HSTS header
 trixies-wish.nz: could not connect to host
+trkpuls.tk: could not connect to host
 trollme.me: could not connect to host
 trunkjunk.co: did not receive HSTS header
 trusitio.com: did not receive HSTS header
 trusteecar.com: did not receive HSTS header
 trustmeimfancy.com: could not connect to host
 trybind.com: could not connect to host
 tryoneday.co: did not receive HSTS header
 ts2.se: could not connect to host
@@ -4435,17 +4425,17 @@ unbanthe.net: could not connect to host
 unblocked-networks.org: could not connect to host
 unblocked.host: could not connect to host
 unblocked.today: did not receive HSTS header
 unblocked.win: could not connect to host
 unblocked.works: did not receive HSTS header
 unblocked.world: did not receive HSTS header
 unccdesign.club: could not connect to host
 unclegen.xyz: could not connect to host
-undernet.uy: did not receive HSTS header
+undernet.uy: could not connect to host
 unfiltered.nyc: did not receive HSTS header
 unfuddle.cn: could not connect to host
 uni-games.com: could not connect to host
 unicooo.com: could not connect to host
 unison.com: did not receive HSTS header
 unisyssecurity.com: did not receive HSTS header
 unitedcyberdevelopment.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 unitlabs.net: could not connect to host
@@ -4472,17 +4462,17 @@ us-immigration.com: did not receive HSTS
 usaa.com: did not receive HSTS header
 usbtypeccompliant.com: could not connect to host
 uscitizenship.info: did not receive HSTS header
 uscurrency.gov: did not receive HSTS header
 used-in.jp: did not receive HSTS header
 usercare.com: did not receive HSTS header
 userify.com: did not receive HSTS header
 ustr.gov: max-age too low: 86400
-utilitarianism.net: could not connect to host
+utilitarianism.net: did not receive HSTS header
 utleieplassen.no: could not connect to host
 utopiagalaxy.space: could not connect to host
 utopianhomespa.com: did not receive HSTS header
 utumno.ch: could not connect to host
 utvbloggen.se: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 uvarov.pw: did not receive HSTS header
 uy.search.yahoo.com: did not receive HSTS header
 uz.search.yahoo.com: did not receive HSTS header
@@ -4503,17 +4493,16 @@ vanderkley.it: could not connect to host
 vanderstraeten.dynv6.net: could not connect to host
 vanestack.com: could not connect to host
 vanetv.com: could not connect to host
 vanitas.xyz: could not connect to host
 vanitynailworkz.com: could not connect to host
 vanlaanen.com: did not receive HSTS header
 vansieleghem.com: could not connect to host
 vasanth.org: did not receive HSTS header
-vbazile.com: could not connect to host
 vbulletin-russia.com: could not connect to host
 vbulletinrussia.com: could not connect to host
 vcdove.com: did not receive HSTS header
 vcr.re: could not connect to host
 veblen.com: could not connect to host
 vechkasov.ru: did not receive HSTS header
 vehent.org: did not receive HSTS header
 vemokin.net: did not receive HSTS header
@@ -4550,17 +4539,16 @@ vissanum.com: did not receive HSTS heade
 vistarait.com: did not receive HSTS header
 vitagenda.nl: could not connect to host
 vitalorange.com: did not receive HSTS header
 vitapingu.de: could not connect to host
 viva-french.com: did not receive HSTS header
 vlastimilburian.cz: did not receive HSTS header
 vlora.city: could not connect to host
 vm0.eu: did not receive HSTS header
-vmc.co.id: could not connect to host
 vmrdev.com: could not connect to host
 voceinveste.com: did not receive HSTS header
 vodpay.com: could not connect to host
 vodpay.net: could not connect to host
 vodpay.org: could not connect to host
 voicesuk.co.uk: did not receive HSTS header
 voidpay.com: could not connect to host
 voidpay.net: could not connect to host
@@ -4723,17 +4711,17 @@ wowapi.org: could not connect to host
 wphostingspot.com: did not receive HSTS header
 wpmetadatastandardsproject.org: could not connect to host
 writeapp.me: did not receive HSTS header
 wsscompany.com.ve: could not connect to host
 wufu.org: did not receive HSTS header
 wuhengmin.com: did not receive HSTS header
 wurzelzwerg.net: could not connect to host
 wusx.club: could not connect to host
-www.apollo-auto.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
+www.apollo-auto.com: could not connect to host
 www.braintreepayments.com: did not receive HSTS header
 www.calyxinstitute.org: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
 www.cueup.com: could not connect to host
 www.cyveillance.com: did not receive HSTS header
 www.developer.mydigipass.com: could not connect to host
 www.elanex.biz: did not receive HSTS header
 www.gamesdepartment.co.uk: did not receive HSTS header
 www.gmail.com: did not receive HSTS header (error ignored - included regardless)
@@ -4748,17 +4736,19 @@ www.neonisi.com: could not connect to ho
 www.paycheckrecords.com: did not receive HSTS header
 www.rme.li: did not receive HSTS header
 www.sandbox.mydigipass.com: could not connect to host
 www.surfeasy.com: did not receive HSTS header
 www.zenpayroll.com: did not receive HSTS header
 www3.info: could not connect to host
 wxukang.cn: could not connect to host
 wyzphoto.nl: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 121"  data: no]
+x-case.de: max-age too low: 0
 x2w.io: could not connect to host
+x3led.com: could not connect to host
 xa.search.yahoo.com: did not receive HSTS header
 xandocs.com: could not connect to host
 xatr0z.org: could not connect to host
 xavierbarroso.com: could not connect to host
 xcoop.me: could not connect to host
 xellos.ga: could not connect to host
 xellos.ml: could not connect to host
 xendo.net: could not connect to host
@@ -4878,16 +4868,17 @@ zehntner.ch: could not connect to host
 zeitpunkt-kulturmagazin.de: did not receive HSTS header
 zelezny.uk: did not receive HSTS header
 zelfstandigemakelaars.net: could not connect to host
 zenpayroll.com: did not receive HSTS header
 zentraler-kreditausschuss.de: did not receive HSTS header
 zentralwolke.de: did not receive HSTS header
 zera.com.au: could not connect to host
 zerolab.org: could not connect to host
+zertif.info: could not connect to host
 zerudi.com: did not receive HSTS header
 zett4.me: could not connect to host
 zeytin.pro: could not connect to host
 zh.search.yahoo.com: did not receive HSTS header
 zhaojin97.cn: did not receive HSTS header
 zhendingresources.com: could not connect to host
 zinenapse.info: could not connect to host
 zirtue.io: could not connect to host
--- a/security/manager/ssl/nsSTSPreloadList.inc
+++ b/security/manager/ssl/nsSTSPreloadList.inc
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*****************************************************************************/
 /* This is an automatically generated file. If you're not                    */
 /* nsSiteSecurityService.cpp, you shouldn't be #including it.     */
 /*****************************************************************************/
 
 #include <stdint.h>
-const PRTime gPreloadListExpirationTime = INT64_C(1498665744919000);
+const PRTime gPreloadListExpirationTime = INT64_C(1498750404667000);
 
 static const char kSTSHostTable[] = {
   /* "0.me.uk", true */ '0', '.', 'm', 'e', '.', 'u', 'k', '\0',
   /* "007-preisvergleich.de", true */ '0', '0', '7', '-', 'p', 'r', 'e', 'i', 's', 'v', 'e', 'r', 'g', 'l', 'e', 'i', 'c', 'h', '.', 'd', 'e', '\0',
   /* "0100dev.com", true */ '0', '1', '0', '0', 'd', 'e', 'v', '.', 'c', 'o', 'm', '\0',
   /* "0100dev.nl", true */ '0', '1', '0', '0', 'd', 'e', 'v', '.', 'n', 'l', '\0',
   /* "01electronica.com.ar", true */ '0', '1', 'e', 'l', 'e', 'c', 't', 'r', 'o', 'n', 'i', 'c', 'a', '.', 'c', 'o', 'm', '.', 'a', 'r', '\0',
   /* "01seguridad.com.ar", true */ '0', '1', 's', 'e', 'g', 'u', 'r', 'i', 'd', 'a', 'd', '.', 'c', 'o', 'm', '.', 'a', 'r', '\0',
@@ -33,17 +33,16 @@ static const char kSTSHostTable[] = {
   /* "0x52.net", true */ '0', 'x', '5', '2', '.', 'n', 'e', 't', '\0',
   /* "0x52.org", true */ '0', 'x', '5', '2', '.', 'o', 'r', 'g', '\0',
   /* "0x539.pw", true */ '0', 'x', '5', '3', '9', '.', 'p', 'w', '\0',
   /* "0x65.net", true */ '0', 'x', '6', '5', '.', 'n', 'e', 't', '\0',
   /* "0x90.fi", true */ '0', 'x', '9', '0', '.', 'f', 'i', '\0',
   /* "0x90.io", true */ '0', 'x', '9', '0', '.', 'i', 'o', '\0',
   /* "0xAA55.me", true */ '0', 'x', 'A', 'A', '5', '5', '.', 'm', 'e', '\0',
   /* "0xaa55.me", true */ '0', 'x', 'a', 'a', '5', '5', '.', 'm', 'e', '\0',
-  /* "0xacab.org", true */ '0', 'x', 'a', 'c', 'a', 'b', '.', 'o', 'r', 'g', '\0',
   /* "0xda.de", true */ '0', 'x', 'd', 'a', '.', 'd', 'e', '\0',
   /* "0xdefaced.de", true */ '0', 'x', 'd', 'e', 'f', 'a', 'c', 'e', 'd', '.', 'd', 'e', '\0',
   /* "0xee.eu", true */ '0', 'x', 'e', 'e', '.', 'e', 'u', '\0',
   /* "0xfc.de", true */ '0', 'x', 'f', 'c', '.', 'd', 'e', '\0',
   /* "0xn.de", true */ '0', 'x', 'n', '.', 'd', 'e', '\0',
   /* "10000v.ru", true */ '1', '0', '0', '0', '0', 'v', '.', 'r', 'u', '\0',
   /* "1000minds.com", true */ '1', '0', '0', '0', 'm', 'i', 'n', 'd', 's', '.', 'c', 'o', 'm', '\0',
   /* "1000serien.com", true */ '1', '0', '0', '0', 's', 'e', 'r', 'i', 'e', 'n', '.', 'c', 'o', 'm', '\0',
@@ -159,26 +158,26 @@ static const char kSTSHostTable[] = {
   /* "3dmedium.de", true */ '3', 'd', 'm', 'e', 'd', 'i', 'u', 'm', '.', 'd', 'e', '\0',
   /* "3do3dont.com", true */ '3', 'd', 'o', '3', 'd', 'o', 'n', 't', '.', 'c', 'o', 'm', '\0',
   /* "3r.org.uk", true */ '3', 'r', '.', 'o', 'r', 'g', '.', 'u', 'k', '\0',
   /* "3s-hosting.de", true */ '3', 's', '-', 'h', 'o', 's', 't', 'i', 'n', 'g', '.', 'd', 'e', '\0',
   /* "3timegear.com", true */ '3', 't', 'i', 'm', 'e', 'g', 'e', 'a', 'r', '.', 'c', 'o', 'm', '\0',
   /* "4-1-where.com", true */ '4', '-', '1', '-', 'w', 'h', 'e', 'r', 'e', '.', 'c', 'o', 'm', '\0',
   /* "4-it.de", true */ '4', '-', 'i', 't', '.', 'd', 'e', '\0',
   /* "403.ch", true */ '4', '0', '3', '.', 'c', 'h', '\0',
+  /* "404404.info", true */ '4', '0', '4', '4', '0', '4', '.', 'i', 'n', 'f', 'o', '\0',
   /* "4096bit.de", true */ '4', '0', '9', '6', 'b', 'i', 't', '.', 'd', 'e', '\0',
   /* "41-where.com", true */ '4', '1', '-', 'w', 'h', 'e', 'r', 'e', '.', 'c', 'o', 'm', '\0',
   /* "41where.com", true */ '4', '1', 'w', 'h', 'e', 'r', 'e', '.', 'c', 'o', 'm', '\0',
   /* "439191.com", true */ '4', '3', '9', '1', '9', '1', '.', 'c', 'o', 'm', '\0',
   /* "441jj.com", true */ '4', '4', '1', 'j', 'j', '.', 'c', 'o', 'm', '\0',
   /* "4500.co.il", true */ '4', '5', '0', '0', '.', 'c', 'o', '.', 'i', 'l', '\0',
   /* "491mhz.net", true */ '4', '9', '1', 'm', 'h', 'z', '.', 'n', 'e', 't', '\0',
   /* "4azino777.ru", true */ '4', 'a', 'z', 'i', 'n', 'o', '7', '7', '7', '.', 'r', 'u', '\0',
   /* "4d2.xyz", true */ '4', 'd', '2', '.', 'x', 'y', 'z', '\0',
-  /* "4eyes.ch", false */ '4', 'e', 'y', 'e', 's', '.', 'c', 'h', '\0',
   /* "4g-server.eu", false */ '4', 'g', '-', 's', 'e', 'r', 'v', 'e', 'r', '.', 'e', 'u', '\0',
   /* "4loc.us", true */ '4', 'l', 'o', 'c', '.', 'u', 's', '\0',
   /* "4miners.net", true */ '4', 'm', 'i', 'n', 'e', 'r', 's', '.', 'n', 'e', 't', '\0',
   /* "4ourty2.org", true */ '4', 'o', 'u', 'r', 't', 'y', '2', '.', 'o', 'r', 'g', '\0',
   /* "4project.co.il", true */ '4', 'p', 'r', 'o', 'j', 'e', 'c', 't', '.', 'c', 'o', '.', 'i', 'l', '\0',
   /* "4th-ave-studio.com", true */ '4', 't', 'h', '-', 'a', 'v', 'e', '-', 's', 't', 'u', 'd', 'i', 'o', '.', 'c', 'o', 'm', '\0',
   /* "4vf.de", true */ '4', 'v', 'f', '.', 'd', 'e', '\0',
   /* "4w-performers.link", false */ '4', 'w', '-', 'p', 'e', 'r', 'f', 'o', 'r', 'm', 'e', 'r', 's', '.', 'l', 'i', 'n', 'k', '\0',
@@ -489,17 +488,16 @@ static const char kSTSHostTable[] = {
   /* "airhart.me", true */ 'a', 'i', 'r', 'h', 'a', 'r', 't', '.', 'm', 'e', '\0',
   /* "airhelp.com", true */ 'a', 'i', 'r', 'h', 'e', 'l', 'p', '.', 'c', 'o', 'm', '\0',
   /* "airlea.com", true */ 'a', 'i', 'r', 'l', 'e', 'a', '.', 'c', 'o', 'm', '\0',
   /* "airlinecheckins.com", true */ 'a', 'i', 'r', 'l', 'i', 'n', 'e', 'c', 'h', 'e', 'c', 'k', 'i', 'n', 's', '.', 'c', 'o', 'm', '\0',
   /* "airnow.gov", true */ 'a', 'i', 'r', 'n', 'o', 'w', '.', 'g', 'o', 'v', '\0',
   /* "airpbx.com", true */ 'a', 'i', 'r', 'p', 'b', 'x', '.', 'c', 'o', 'm', '\0',
   /* "airsoft.ch", true */ 'a', 'i', 'r', 's', 'o', 'f', 't', '.', 'c', 'h', '\0',
   /* "airvuz.com", true */ 'a', 'i', 'r', 'v', 'u', 'z', '.', 'c', 'o', 'm', '\0',
-  /* "aisle3.space", true */ 'a', 'i', 's', 'l', 'e', '3', '.', 's', 'p', 'a', 'c', 'e', '\0',
   /* "aistockcharts.com", true */ 'a', 'i', 's', 't', 'o', 'c', 'k', 'c', 'h', 'a', 'r', 't', 's', '.', 'c', 'o', 'm', '\0',
   /* "aiticon.com", true */ 'a', 'i', 't', 'i', 'c', 'o', 'n', '.', 'c', 'o', 'm', '\0',
   /* "aitosoftware.com", true */ 'a', 'i', 't', 'o', 's', 'o', 'f', 't', 'w', 'a', 'r', 'e', '.', 'c', 'o', 'm', '\0',
   /* "aivd.lol", true */ 'a', 'i', 'v', 'd', '.', 'l', 'o', 'l', '\0',
   /* "aiwdirect.com", true */ 'a', 'i', 'w', 'd', 'i', 'r', 'e', 'c', 't', '.', 'c', 'o', 'm', '\0',
   /* "ajouin.com", true */ 'a', 'j', 'o', 'u', 'i', 'n', '.', 'c', 'o', 'm', '\0',
   /* "akachanikuji.com", true */ 'a', 'k', 'a', 'c', 'h', 'a', 'n', 'i', 'k', 'u', 'j', 'i', '.', 'c', 'o', 'm', '\0',
   /* "akaoma.com", true */ 'a', 'k', 'a', 'o', 'm', 'a', '.', 'c', 'o', 'm', '\0',
@@ -1017,19 +1015,16 @@ static const char kSTSHostTable[] = {
   /* "askmagicconch.com", true */ 'a', 's', 'k', 'm', 'a', 'g', 'i', 'c', 'c', 'o', 'n', 'c', 'h', '.', 'c', 'o', 'm', '\0',
   /* "askme24.de", true */ 'a', 's', 'k', 'm', 'e', '2', '4', '.', 'd', 'e', '\0',
   /* "askwhy.cz", true */ 'a', 's', 'k', 'w', 'h', 'y', '.', 'c', 'z', '\0',
   /* "askwhy.eu", true */ 'a', 's', 'k', 'w', 'h', 'y', '.', 'e', 'u', '\0',
   /* "aspargesgaarden.no", true */ 'a', 's', 'p', 'a', 'r', 'g', 'e', 's', 'g', 'a', 'a', 'r', 'd', 'e', 'n', '.', 'n', 'o', '\0',
   /* "asphaltfruehling.de", true */ 'a', 's', 'p', 'h', 'a', 'l', 't', 'f', 'r', 'u', 'e', 'h', 'l', 'i', 'n', 'g', '.', 'd', 'e', '\0',
   /* "asphyxia.su", true */ 'a', 's', 'p', 'h', 'y', 'x', 'i', 'a', '.', 's', 'u', '\0',
   /* "aspires.co.jp", true */ 'a', 's', 'p', 'i', 'r', 'e', 's', '.', 'c', 'o', '.', 'j', 'p', '\0',
-  /* "asr.li", true */ 'a', 's', 'r', '.', 'l', 'i', '\0',
-  /* "asr.rocks", true */ 'a', 's', 'r', '.', 'r', 'o', 'c', 'k', 's', '\0',
-  /* "asr.solar", true */ 'a', 's', 'r', '.', 's', 'o', 'l', 'a', 'r', '\0',
   /* "assemble-together.org", true */ 'a', 's', 's', 'e', 'm', 'b', 'l', 'e', '-', 't', 'o', 'g', 'e', 't', 'h', 'e', 'r', '.', 'o', 'r', 'g', '\0',
   /* "assindia.nl", true */ 'a', 's', 's', 'i', 'n', 'd', 'i', 'a', '.', 'n', 'l', '\0',
   /* "assurancesmons.be", true */ 'a', 's', 's', 'u', 'r', 'a', 'n', 'c', 'e', 's', 'm', 'o', 'n', 's', '.', 'b', 'e', '\0',
   /* "asta-bar.de", true */ 'a', 's', 't', 'a', '-', 'b', 'a', 'r', '.', 'd', 'e', '\0',
   /* "astengox.com", true */ 'a', 's', 't', 'e', 'n', 'g', 'o', 'x', '.', 'c', 'o', 'm', '\0',
   /* "astrea-voetbal-groningen.nl", true */ 'a', 's', 't', 'r', 'e', 'a', '-', 'v', 'o', 'e', 't', 'b', 'a', 'l', '-', 'g', 'r', 'o', 'n', 'i', 'n', 'g', 'e', 'n', '.', 'n', 'l', '\0',
   /* "asuhe.cc", true */ 'a', 's', 'u', 'h', 'e', '.', 'c', 'c', '\0',
   /* "asuhe.xyz", true */ 'a', 's', 'u', 'h', 'e', '.', 'x', 'y', 'z', '\0',
@@ -1059,16 +1054,17 @@ static const char kSTSHostTable[] = {
   /* "atisoft.net", true */ 'a', 't', 'i', 's', 'o', 'f', 't', '.', 'n', 'e', 't', '\0',
   /* "atisoft.net.tr", true */ 'a', 't', 'i', 's', 'o', 'f', 't', '.', 'n', 'e', 't', '.', 't', 'r', '\0',
   /* "atisoft.web.tr", true */ 'a', 't', 'i', 's', 'o', 'f', 't', '.', 'w', 'e', 'b', '.', 't', 'r', '\0',
   /* "atitude.com", true */ 'a', 't', 'i', 't', 'u', 'd', 'e', '.', 'c', 'o', 'm', '\0',
   /* "atlantichomes.com.au", true */ 'a', 't', 'l', 'a', 'n', 't', 'i', 'c', 'h', 'o', 'm', 'e', 's', '.', 'c', 'o', 'm', '.', 'a', 'u', '\0',
   /* "atlantischild.hu", true */ 'a', 't', 'l', 'a', 'n', 't', 'i', 's', 'c', 'h', 'i', 'l', 'd', '.', 'h', 'u', '\0',
   /* "atlassian.net", true */ 'a', 't', 'l', 'a', 's', 's', 'i', 'a', 'n', '.', 'n', 'e', 't', '\0',
   /* "atletika.hu", true */ 'a', 't', 'l', 'e', 't', 'i', 'k', 'a', '.', 'h', 'u', '\0',
+  /* "atlseccon.com", true */ 'a', 't', 'l', 's', 'e', 'c', 'c', 'o', 'n', '.', 'c', 'o', 'm', '\0',
   /* "atnis.com", true */ 'a', 't', 'n', 'i', 's', '.', 'c', 'o', 'm', '\0',
   /* "atolm.net", true */ 'a', 't', 'o', 'l', 'm', '.', 'n', 'e', 't', '\0',
   /* "atom-china.org", true */ 'a', 't', 'o', 'm', '-', 'c', 'h', 'i', 'n', 'a', '.', 'o', 'r', 'g', '\0',
   /* "atom.solutions", true */ 'a', 't', 'o', 'm', '.', 's', 'o', 'l', 'u', 't', 'i', 'o', 'n', 's', '\0',
   /* "atom86.net", true */ 'a', 't', 'o', 'm', '8', '6', '.', 'n', 'e', 't', '\0',
   /* "atombase.org", true */ 'a', 't', 'o', 'm', 'b', 'a', 's', 'e', '.', 'o', 'r', 'g', '\0',
   /* "atraining.ru", true */ 'a', 't', 'r', 'a', 'i', 'n', 'i', 'n', 'g', '.', 'r', 'u', '\0',
   /* "atrinik.org", true */ 'a', 't', 'r', 'i', 'n', 'i', 'k', '.', 'o', 'r', 'g', '\0',
@@ -1458,22 +1454,23 @@ static const char kSTSHostTable[] = {
   /* "besthost.cz", true */ 'b', 'e', 's', 't', 'h', 'o', 's', 't', '.', 'c', 'z', '\0',
   /* "bestlashesandbrows.com", true */ 'b', 'e', 's', 't', 'l', 'a', 's', 'h', 'e', 's', 'a', 'n', 'd', 'b', 'r', 'o', 'w', 's', '.', 'c', 'o', 'm', '\0',
   /* "bestlashesandbrows.hu", true */ 'b', 'e', 's', 't', 'l', 'a', 's', 'h', 'e', 's', 'a', 'n', 'd', 'b', 'r', 'o', 'w', 's', '.', 'h', 'u', '\0',
   /* "bestmotherfucking.website", true */ 'b', 'e', 's', 't', 'm', 'o', 't', 'h', 'e', 'r', 'f', 'u', 'c', 'k', 'i', 'n', 'g', '.', 'w', 'e', 'b', 's', 'i', 't', 'e', '\0',
   /* "bestorangeseo.com", true */ 'b', 'e', 's', 't', 'o', 'r', 'a', 'n', 'g', 'e', 's', 'e', 'o', '.', 'c', 'o', 'm', '\0',
   /* "bestperfumebrands.com", true */ 'b', 'e', 's', 't', 'p', 'e', 'r', 'f', 'u', 'm', 'e', 'b', 'r', 'a', 'n', 'd', 's', '.', 'c', 'o', 'm', '\0',
   /* "bestseries.tv", true */ 'b', 'e', 's', 't', 's', 'e', 'r', 'i', 'e', 's', '.', 't', 'v', '\0',
   /* "betaclean.fr", true */ 'b', 'e', 't', 'a', 'c', 'l', 'e', 'a', 'n', '.', 'f', 'r', '\0',
+  /* "betaworx.de", true */ 'b', 'e', 't', 'a', 'w', 'o', 'r', 'x', '.', 'd', 'e', '\0',
+  /* "betaworx.eu", true */ 'b', 'e', 't', 'a', 'w', 'o', 'r', 'x', '.', 'e', 'u', '\0',
   /* "betlander.com", true */ 'b', 'e', 't', 'l', 'a', 'n', 'd', 'e', 'r', '.', 'c', 'o', 'm', '\0',
   /* "betobaccofree.gov", true */ 'b', 'e', 't', 'o', 'b', 'a', 'c', 'c', 'o', 'f', 'r', 'e', 'e', '.', 'g', 'o', 'v', '\0',
   /* "betonmoney.com", true */ 'b', 'e', 't', 'o', 'n', 'm', 'o', 'n', 'e', 'y', '.', 'c', 'o', 'm', '\0',
   /* "betpamm.com", true */ 'b', 'e', 't', 'p', 'a', 'm', 'm', '.', 'c', 'o', 'm', '\0',
   /* "betterbabyshop.com.au", true */ 'b', 'e', 't', 't', 'e', 'r', 'b', 'a', 'b', 'y', 's', 'h', 'o', 'p', '.', 'c', 'o', 'm', '.', 'a', 'u', '\0',
-  /* "bettercrypto.org", true */ 'b', 'e', 't', 't', 'e', 'r', 'c', 'r', 'y', 'p', 't', 'o', '.', 'o', 'r', 'g', '\0',
   /* "betterhelp.com", true */ 'b', 'e', 't', 't', 'e', 'r', 'h', 'e', 'l', 'p', '.', 'c', 'o', 'm', '\0',
   /* "betterlifemakers.com", true */ 'b', 'e', 't', 't', 'e', 'r', 'l', 'i', 'f', 'e', 'm', 'a', 'k', 'e', 'r', 's', '.', 'c', 'o', 'm', '\0',
   /* "bettertest.it", true */ 'b', 'e', 't', 't', 'e', 'r', 't', 'e', 's', 't', '.', 'i', 't', '\0',
   /* "bettingbusiness.ru", true */ 'b', 'e', 't', 't', 'i', 'n', 'g', 'b', 'u', 's', 'i', 'n', 'e', 's', 's', '.', 'r', 'u', '\0',
   /* "bettolinokitchen.com", true */ 'b', 'e', 't', 't', 'o', 'l', 'i', 'n', 'o', 'k', 'i', 't', 'c', 'h', 'e', 'n', '.', 'c', 'o', 'm', '\0',
   /* "bettrlifeapp.com", true */ 'b', 'e', 't', 't', 'r', 'l', 'i', 'f', 'e', 'a', 'p', 'p', '.', 'c', 'o', 'm', '\0',
   /* "betulashop.ch", true */ 'b', 'e', 't', 'u', 'l', 'a', 's', 'h', 'o', 'p', '.', 'c', 'h', '\0',
   /* "beulahtabernacle.com", true */ 'b', 'e', 'u', 'l', 'a', 'h', 't', 'a', 'b', 'e', 'r', 'n', 'a', 'c', 'l', 'e', '.', 'c', 'o', 'm', '\0',
@@ -1781,16 +1778,17 @@ static const char kSTSHostTable[] = {
   /* "bohaishibei.com", true */ 'b', 'o', 'h', 'a', 'i', 's', 'h', 'i', 'b', 'e', 'i', '.', 'c', 'o', 'm', '\0',
   /* "bohramt.de", true */ 'b', 'o', 'h', 'r', 'a', 'm', 't', '.', 'd', 'e', '\0',
   /* "boiadeirodeberna.com", true */ 'b', 'o', 'i', 'a', 'd', 'e', 'i', 'r', 'o', 'd', 'e', 'b', 'e', 'r', 'n', 'a', '.', 'c', 'o', 'm', '\0',
   /* "boilesen.com", true */ 'b', 'o', 'i', 'l', 'e', 's', 'e', 'n', '.', 'c', 'o', 'm', '\0',
   /* "boiseonlinemall.com", true */ 'b', 'o', 'i', 's', 'e', 'o', 'n', 'l', 'i', 'n', 'e', 'm', 'a', 'l', 'l', '.', 'c', 'o', 'm', '\0',
   /* "bokeyy.com", true */ 'b', 'o', 'k', 'e', 'y', 'y', '.', 'c', 'o', 'm', '\0',
   /* "bolt.cm", true */ 'b', 'o', 'l', 't', '.', 'c', 'm', '\0',
   /* "boltdata.io", false */ 'b', 'o', 'l', 't', 'd', 'a', 't', 'a', '.', 'i', 'o', '\0',
+  /* "bombsquad.studio", true */ 'b', 'o', 'm', 'b', 's', 'q', 'u', 'a', 'd', '.', 's', 't', 'u', 'd', 'i', 'o', '\0',
   /* "bondpro.gov", true */ 'b', 'o', 'n', 'd', 'p', 'r', 'o', '.', 'g', 'o', 'v', '\0',
   /* "bondskampeerder.nl", true */ 'b', 'o', 'n', 'd', 's', 'k', 'a', 'm', 'p', 'e', 'e', 'r', 'd', 'e', 'r', '.', 'n', 'l', '\0',
   /* "bonifacius.be", true */ 'b', 'o', 'n', 'i', 'f', 'a', 'c', 'i', 'u', 's', '.', 'b', 'e', '\0',
   /* "bonnyprints.at", true */ 'b', 'o', 'n', 'n', 'y', 'p', 'r', 'i', 'n', 't', 's', '.', 'a', 't', '\0',
   /* "bonnyprints.ch", true */ 'b', 'o', 'n', 'n', 'y', 'p', 'r', 'i', 'n', 't', 's', '.', 'c', 'h', '\0',
   /* "bonnyprints.es", true */ 'b', 'o', 'n', 'n', 'y', 'p', 'r', 'i', 'n', 't', 's', '.', 'e', 's', '\0',
   /* "bonnyprints.fr", true */ 'b', 'o', 'n', 'n', 'y', 'p', 'r', 'i', 'n', 't', 's', '.', 'f', 'r', '\0',
   /* "bonobo.cz", true */ 'b', 'o', 'n', 'o', 'b', 'o', '.', 'c', 'z', '\0',
@@ -2013,17 +2011,16 @@ static const char kSTSHostTable[] = {
   /* "bulbgenie.com", true */ 'b', 'u', 'l', 'b', 'g', 'e', 'n', 'i', 'e', '.', 'c', 'o', 'm', '\0',
   /* "buldogueingles.com.br", true */ 'b', 'u', 'l', 'd', 'o', 'g', 'u', 'e', 'i', 'n', 'g', 'l', 'e', 's', '.', 'c', 'o', 'm', '.', 'b', 'r', '\0',
   /* "bulkcandystore.com", true */ 'b', 'u', 'l', 'k', 'c', 'a', 'n', 'd', 'y', 's', 't', 'o', 'r', 'e', '.', 'c', 'o', 'm', '\0',
   /* "bulktrade.de", true */ 'b', 'u', 'l', 'k', 't', 'r', 'a', 'd', 'e', '.', 'd', 'e', '\0',
   /* "bullbits.com", true */ 'b', 'u', 'l', 'l', 'b', 'i', 't', 's', '.', 'c', 'o', 'm', '\0',
   /* "bulldog-hosting.de", true */ 'b', 'u', 'l', 'l', 'd', 'o', 'g', '-', 'h', 'o', 's', 't', 'i', 'n', 'g', '.', 'd', 'e', '\0',
   /* "bullterrier.me", true */ 'b', 'u', 'l', 'l', 't', 'e', 'r', 'r', 'i', 'e', 'r', '.', 'm', 'e', '\0',
   /* "bulmastife.com.br", true */ 'b', 'u', 'l', 'm', 'a', 's', 't', 'i', 'f', 'e', '.', 'c', 'o', 'm', '.', 'b', 'r', '\0',
-  /* "bunbomenu.de", true */ 'b', 'u', 'n', 'b', 'o', 'm', 'e', 'n', 'u', '.', 'd', 'e', '\0',
   /* "bunbun.be", false */ 'b', 'u', 'n', 'b', 'u', 'n', '.', 'b', 'e', '\0',
   /* "bund-von-theramore.de", true */ 'b', 'u', 'n', 'd', '-', 'v', 'o', 'n', '-', 't', 'h', 'e', 'r', 'a', 'm', 'o', 'r', 'e', '.', 'd', 'e', '\0',
   /* "bundaberg.com", true */ 'b', 'u', 'n', 'd', 'a', 'b', 'e', 'r', 'g', '.', 'c', 'o', 'm', '\0',
   /* "bundespolizei-forum.de", true */ 'b', 'u', 'n', 'd', 'e', 's', 'p', 'o', 'l', 'i', 'z', 'e', 'i', '-', 'f', 'o', 'r', 'u', 'm', '.', 'd', 'e', '\0',
   /* "bunkyo-life.com", true */ 'b', 'u', 'n', 'k', 'y', 'o', '-', 'l', 'i', 'f', 'e', '.', 'c', 'o', 'm', '\0',
   /* "bunsenlabs.org", true */ 'b', 'u', 'n', 's', 'e', 'n', 'l', 'a', 'b', 's', '.', 'o', 'r', 'g', '\0',
   /* "buonventosbt.eu", true */ 'b', 'u', 'o', 'n', 'v', 'e', 'n', 't', 'o', 's', 'b', 't', '.', 'e', 'u', '\0',
   /* "bureaubolster.nl", true */ 'b', 'u', 'r', 'e', 'a', 'u', 'b', 'o', 'l', 's', 't', 'e', 'r', '.', 'n', 'l', '\0',
@@ -2106,17 +2103,16 @@ static const char kSTSHostTable[] = {
   /* "bztech.com.br", true */ 'b', 'z', 't', 'e', 'c', 'h', '.', 'c', 'o', 'm', '.', 'b', 'r', '\0',
   /* "bzv-fr.eu", true */ 'b', 'z', 'v', '-', 'f', 'r', '.', 'e', 'u', '\0',
   /* "c-path.org", true */ 'c', '-', 'p', 'a', 't', 'h', '.', 'o', 'r', 'g', '\0',
   /* "c-rickroll-v.pw", true */ 'c', '-', 'r', 'i', 'c', 'k', 'r', 'o', 'l', 'l', '-', 'v', '.', 'p', 'w', '\0',
   /* "c-shock.org", true */ 'c', '-', 's', 'h', 'o', 'c', 'k', '.', 'o', 'r', 'g', '\0',
   /* "c-webdesign.net", true */ 'c', '-', 'w', 'e', 'b', 'd', 'e', 's', 'i', 'g', 'n', '.', 'n', 'e', 't', '\0',
   /* "c-world.co.uk", true */ 'c', '-', 'w', 'o', 'r', 'l', 'd', '.', 'c', 'o', '.', 'u', 'k', '\0',
   /* "c.cc", true */ 'c', '.', 'c', 'c', '\0',
-  /* "c0rn3j.com", true */ 'c', '0', 'r', 'n', '3', 'j', '.', 'c', 'o', 'm', '\0',
   /* "c16t.uk", true */ 'c', '1', '6', 't', '.', 'u', 'k', '\0',
   /* "c3vo.de", true */ 'c', '3', 'v', 'o', '.', 'd', 'e', '\0',
   /* "c3w.at", true */ 'c', '3', 'w', '.', 'a', 't', '\0',
   /* "c4.hk", true */ 'c', '4', '.', 'h', 'k', '\0',
   /* "c4539.com", true */ 'c', '4', '5', '3', '9', '.', 'c', 'o', 'm', '\0',
   /* "c4k3.net", true */ 'c', '4', 'k', '3', '.', 'n', 'e', 't', '\0',
   /* "ca-key.de", true */ 'c', 'a', '-', 'k', 'e', 'y', '.', 'd', 'e', '\0',
   /* "ca-terminal-multiservices.fr", true */ 'c', 'a', '-', 't', 'e', 'r', 'm', 'i', 'n', 'a', 'l', '-', 'm', 'u', 'l', 't', 'i', 's', 'e', 'r', 'v', 'i', 'c', 'e', 's', '.', 'f', 'r', '\0',
@@ -2236,17 +2232,16 @@ static const char kSTSHostTable[] = {
   /* "carauctionnetwork.com", true */ 'c', 'a', 'r', 'a', 'u', 'c', 't', 'i', 'o', 'n', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'c', 'o', 'm', '\0',
   /* "carauctionsalabama.com", true */ 'c', 'a', 'r', 'a', 'u', 'c', 't', 'i', 'o', 'n', 's', 'a', 'l', 'a', 'b', 'a', 'm', 'a', '.', 'c', 'o', 'm', '\0',
   /* "carauctionscarolina.com", true */ 'c', 'a', 'r', 'a', 'u', 'c', 't', 'i', 'o', 'n', 's', 'c', 'a', 'r', 'o', 'l', 'i', 'n', 'a', '.', 'c', 'o', 'm', '\0',
   /* "carauctionsgeorgia.com", true */ 'c', 'a', 'r', 'a', 'u', 'c', 't', 'i', 'o', 'n', 's', 'g', 'e', 'o', 'r', 'g', 'i', 'a', '.', 'c', 'o', 'm', '\0',
   /* "carbon12.org", true */ 'c', 'a', 'r', 'b', 'o', 'n', '1', '2', '.', 'o', 'r', 'g', '\0',
   /* "carbon12.software", true */ 'c', 'a', 'r', 'b', 'o', 'n', '1', '2', '.', 's', 'o', 'f', 't', 'w', 'a', 'r', 'e', '\0',
   /* "carboneselectricosnettosl.info", false */ 'c', 'a', 'r', 'b', 'o', 'n', 'e', 's', 'e', 'l', 'e', 'c', 't', 'r', 'i', 'c', 'o', 's', 'n', 'e', 't', 't', 'o', 's', 'l', '.', 'i', 'n', 'f', 'o', '\0',
   /* "carbonmade.com", false */ 'c', 'a', 'r', 'b', 'o', 'n', 'm', 'a', 'd', 'e', '.', 'c', 'o', 'm', '\0',
-  /* "carck.co.uk", true */ 'c', 'a', 'r', 'c', 'k', '.', 'c', 'o', '.', 'u', 'k', '\0',
   /* "card-toka.jp", true */ 'c', 'a', 'r', 'd', '-', 't', 'o', 'k', 'a', '.', 'j', 'p', '\0',
   /* "cardranking.jp", true */ 'c', 'a', 'r', 'd', 'r', 'a', 'n', 'k', 'i', 'n', 'g', '.', 'j', 'p', '\0',
   /* "cardrecovery.fr", true */ 'c', 'a', 'r', 'd', 'r', 'e', 'c', 'o', 'v', 'e', 'r', 'y', '.', 'f', 'r', '\0',
   /* "cardse.net", true */ 'c', 'a', 'r', 'd', 's', 'e', '.', 'n', 'e', 't', '\0',
   /* "careerstuds.com", true */ 'c', 'a', 'r', 'e', 'e', 'r', 's', 't', 'u', 'd', 's', '.', 'c', 'o', 'm', '\0',
   /* "caremad.io", true */ 'c', 'a', 'r', 'e', 'm', 'a', 'd', '.', 'i', 'o', '\0',
   /* "caretta.co.uk", true */ 'c', 'a', 'r', 'e', 't', 't', 'a', '.', 'c', 'o', '.', 'u', 'k', '\0',
   /* "carey.bio", true */ 'c', 'a', 'r', 'e', 'y', '.', 'b', 'i', 'o', '\0',
@@ -2449,16 +2444,17 @@ static const char kSTSHostTable[] = {
   /* "cheetahwerx.com", true */ 'c', 'h', 'e', 'e', 't', 'a', 'h', 'w', 'e', 'r', 'x', '.', 'c', 'o', 'm', '\0',
   /* "cheez.systems", true */ 'c', 'h', 'e', 'e', 'z', '.', 's', 'y', 's', 't', 'e', 'm', 's', '\0',
   /* "chelseafs.co.uk", true */ 'c', 'h', 'e', 'l', 's', 'e', 'a', 'f', 's', '.', 'c', 'o', '.', 'u', 'k', '\0',
   /* "chenapartment.com", true */ 'c', 'h', 'e', 'n', 'a', 'p', 'a', 'r', 't', 'm', 'e', 'n', 't', '.', 'c', 'o', 'm', '\0',
   /* "chengl.com", true */ 'c', 'h', 'e', 'n', 'g', 'l', '.', 'c', 'o', 'm', '\0',
   /* "chenky.com", true */ 'c', 'h', 'e', 'n', 'k', 'y', '.', 'c', 'o', 'm', '\0',
   /* "chennien.com", true */ 'c', 'h', 'e', 'n', 'n', 'i', 'e', 'n', '.', 'c', 'o', 'm', '\0',
   /* "chenzhekl.me", true */ 'c', 'h', 'e', 'n', 'z', 'h', 'e', 'k', 'l', '.', 'm', 'e', '\0',
+  /* "chepaofen.com", true */ 'c', 'h', 'e', 'p', 'a', 'o', 'f', 'e', 'n', '.', 'c', 'o', 'm', '\0',
   /* "cherryonit.com", true */ 'c', 'h', 'e', 'r', 'r', 'y', 'o', 'n', 'i', 't', '.', 'c', 'o', 'm', '\0',
   /* "cherrywoodtech.com", true */ 'c', 'h', 'e', 'r', 'r', 'y', 'w', 'o', 'o', 'd', 't', 'e', 'c', 'h', '.', 'c', 'o', 'm', '\0',
   /* "chesterbrass.uk", true */ 'c', 'h', 'e', 's', 't', 'e', 'r', 'b', 'r', 'a', 's', 's', '.', 'u', 'k', '\0',
   /* "chestnut.cf", true */ 'c', 'h', 'e', 's', 't', 'n', 'u', 't', '.', 'c', 'f', '\0',
   /* "chewey.de", true */ 'c', 'h', 'e', 'w', 'e', 'y', '.', 'd', 'e', '\0',
   /* "chewey.org", true */ 'c', 'h', 'e', 'w', 'e', 'y', '.', 'o', 'r', 'g', '\0',
   /* "chfr.search.yahoo.com", false */ 'c', 'h', 'f', 'r', '.', 's', 'e', 'a', 'r', 'c', 'h', '.', 'y', 'a', 'h', 'o', 'o', '.', 'c', 'o', 'm', '\0',
   /* "chhy.at", true */ 'c', 'h', 'h', 'y', '.', 'a', 't', '\0',
@@ -2602,16 +2598,17 @@ static const char kSTSHostTable[] = {
   /* "classdojo.com", true */ 'c', 'l', 'a', 's', 's', 'd', 'o', 'j', 'o', '.', 'c', 'o', 'm', '\0',
   /* "classicalpilates.ca", true */ 'c', 'l', 'a', 's', 's', 'i', 'c', 'a', 'l', 'p', 'i', 'l', 'a', 't', 'e', 's', '.', 'c', 'a', '\0',
   /* "classicday.nl", true */ 'c', 'l', 'a', 's', 's', 'i', 'c', 'd', 'a', 'y', '.', 'n', 'l', '\0',
   /* "classicshop.ua", true */ 'c', 'l', 'a', 's', 's', 'i', 'c', 's', 'h', 'o', 'p', '.', 'u', 'a', '\0',
   /* "classifiedssa.co.za", true */ 'c', 'l', 'a', 's', 's', 'i', 'f', 'i', 'e', 'd', 's', 's', 'a', '.', 'c', 'o', '.', 'z', 'a', '\0',
   /* "classpoint.cz", true */ 'c', 'l', 'a', 's', 's', 'p', 'o', 'i', 'n', 't', '.', 'c', 'z', '\0',
   /* "claudio4.com", true */ 'c', 'l', 'a', 'u', 'd', 'i', 'o', '4', '.', 'c', 'o', 'm', '\0',
   /* "clawe.de", true */ 'c', 'l', 'a', 'w', 'e', '.', 'd', 'e', '\0',
+  /* "cldly.com", true */ 'c', 'l', 'd', 'l', 'y', '.', 'c', 'o', 'm', '\0',
   /* "clearkonjac.com", true */ 'c', 'l', 'e', 'a', 'r', 'k', 'o', 'n', 'j', 'a', 'c', '.', 'c', 'o', 'm', '\0',
   /* "clearsettle-admin.com", true */ 'c', 'l', 'e', 'a', 'r', 's', 'e', 't', 't', 'l', 'e', '-', 'a', 'd', 'm', 'i', 'n', '.', 'c', 'o', 'm', '\0',
   /* "clearviewwealthprojector.com.au", true */ 'c', 'l', 'e', 'a', 'r', 'v', 'i', 'e', 'w', 'w', 'e', 'a', 'l', 't', 'h', 'p', 'r', 'o', 'j', 'e', 'c', 't', 'o', 'r', '.', 'c', 'o', 'm', '.', 'a', 'u', '\0',
   /* "clevertarget.ru", true */ 'c', 'l', 'e', 'v', 'e', 'r', 't', 'a', 'r', 'g', 'e', 't', '.', 'r', 'u', '\0',
   /* "cleververmarkten.com", true */ 'c', 'l', 'e', 'v', 'e', 'r', 'v', 'e', 'r', 'm', 'a', 'r', 'k', 't', 'e', 'n', '.', 'c', 'o', 'm', '\0',
   /* "cleververmarkten.de", true */ 'c', 'l', 'e', 'v', 'e', 'r', 'v', 'e', 'r', 'm', 'a', 'r', 'k', 't', 'e', 'n', '.', 'd', 'e', '\0',
   /* "clevisto.com", true */ 'c', 'l', 'e', 'v', 'i', 's', 't', 'o', '.', 'c', 'o', 'm', '\0',
   /* "clickclickphish.com", true */ 'c', 'l', 'i', 'c', 'k', 'c', 'l', 'i', 'c', 'k', 'p', 'h', 'i', 's', 'h', '.', 'c', 'o', 'm', '\0',
@@ -2647,16 +2644,17 @@ static const char kSTSHostTable[] = {
   /* "cloud.google.com", true */ 'c', 'l', 'o', 'u', 'd', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm', '\0',
   /* "cloud.gov", false */ 'c', 'l', 'o', 'u', 'd', '.', 'g', 'o', 'v', '\0',
   /* "cloudapps.digital", true */ 'c', 'l', 'o', 'u', 'd', 'a', 'p', 'p', 's', '.', 'd', 'i', 'g', 'i', 't', 'a', 'l', '\0',
   /* "cloudbasedsite.com", true */ 'c', 'l', 'o', 'u', 'd', 'b', 'a', 's', 'e', 'd', 's', 'i', 't', 'e', '.', 'c', 'o', 'm', '\0',
   /* "cloudbolin.es", true */ 'c', 'l', 'o', 'u', 'd', 'b', 'o', 'l', 'i', 'n', '.', 'e', 's', '\0',
   /* "cloudcaprice.net", true */ 'c', 'l', 'o', 'u', 'd', 'c', 'a', 'p', 'r', 'i', 'c', 'e', '.', 'n', 'e', 't', '\0',
   /* "cloudflareonazure.com", true */ 'c', 'l', 'o', 'u', 'd', 'f', 'l', 'a', 'r', 'e', 'o', 'n', 'a', 'z', 'u', 'r', 'e', '.', 'c', 'o', 'm', '\0',
   /* "cloudia.org", true */ 'c', 'l', 'o', 'u', 'd', 'i', 'a', '.', 'o', 'r', 'g', '\0',
+  /* "cloudily.com", true */ 'c', 'l', 'o', 'u', 'd', 'i', 'l', 'y', '.', 'c', 'o', 'm', '\0',
   /* "cloudmigrator365.com", true */ 'c', 'l', 'o', 'u', 'd', 'm', 'i', 'g', 'r', 'a', 't', 'o', 'r', '3', '6', '5', '.', 'c', 'o', 'm', '\0',
   /* "cloudoptimus.com", true */ 'c', 'l', 'o', 'u', 'd', 'o', 'p', 't', 'i', 'm', 'u', 's', '.', 'c', 'o', 'm', '\0',
   /* "cloudpagesforwork.com", true */ 'c', 'l', 'o', 'u', 'd', 'p', 'a', 'g', 'e', 's', 'f', 'o', 'r', 'w', 'o', 'r', 'k', '.', 'c', 'o', 'm', '\0',
   /* "cloudpebble.net", true */ 'c', 'l', 'o', 'u', 'd', 'p', 'e', 'b', 'b', 'l', 'e', '.', 'n', 'e', 't', '\0',
   /* "cloudpipes.com", true */ 'c', 'l', 'o', 'u', 'd', 'p', 'i', 'p', 'e', 's', '.', 'c', 'o', 'm', '\0',
   /* "clouds.webcam", true */ 'c', 'l', 'o', 'u', 'd', 's', '.', 'w', 'e', 'b', 'c', 'a', 'm', '\0',
   /* "cloudsecurityalliance.org", true */ 'c', 'l', 'o', 'u', 'd', 's', 'e', 'c', 'u', 'r', 'i', 't', 'y', 'a', 'l', 'l', 'i', 'a', 'n', 'c', 'e', '.', 'o', 'r', 'g', '\0',
   /* "cloudspace-analytics.com", true */ 'c', 'l', 'o', 'u', 'd', 's', 'p', 'a', 'c', 'e', '-', 'a', 'n', 'a', 'l', 'y', 't', 'i', 'c', 's', '.', 'c', 'o', 'm', '\0',
@@ -2680,17 +2678,16 @@ static const char kSTSHostTable[] = {
   /* "clvs7.com", true */ 'c', 'l', 'v', 's', '7', '.', 'c', 'o', 'm', '\0',
   /* "cmahy.be", true */ 'c', 'm', 'a', 'h', 'y', '.', 'b', 'e', '\0',
   /* "cmdline.org", true */ 'c', 'm', 'd', 'l', 'i', 'n', 'e', '.', 'o', 'r', 'g', '\0',
   /* "cmylife.nl", true */ 'c', 'm', 'y', 'l', 'i', 'f', 'e', '.', 'n', 'l', '\0',
   /* "cnam.net", true */ 'c', 'n', 'a', 'm', '.', 'n', 'e', 't', '\0',
   /* "cnc-lehrgang.de", true */ 'c', 'n', 'c', '-', 'l', 'e', 'h', 'r', 'g', 'a', 'n', 'g', '.', 'd', 'e', '\0',
   /* "cncn.us", true */ 'c', 'n', 'c', 'n', '.', 'u', 's', '\0',
   /* "cnlic.com", true */ 'c', 'n', 'l', 'i', 'c', '.', 'c', 'o', 'm', '\0',
-  /* "cnwage.com", true */ 'c', 'n', 'w', 'a', 'g', 'e', '.', 'c', 'o', 'm', '\0',
   /* "cnwarn.com", true */ 'c', 'n', 'w', 'a', 'r', 'n', '.', 'c', 'o', 'm', '\0',
   /* "co.search.yahoo.com", false */ 'c', 'o', '.', 's', 'e', 'a', 'r', 'c', 'h', '.', 'y', 'a', 'h', 'o', 'o', '.', 'c', 'o', 'm', '\0',
   /* "coachingconsultancy.com", true */ 'c', 'o', 'a', 'c', 'h', 'i', 'n', 'g', 'c', 'o', 'n', 's', 'u', 'l', 't', 'a', 'n', 'c', 'y', '.', 'c', 'o', 'm', '\0',
   /* "coalpointcottage.com", true */ 'c', 'o', 'a', 'l', 'p', 'o', 'i', 'n', 't', 'c', 'o', 't', 't', 'a', 'g', 'e', '.', 'c', 'o', 'm', '\0',
   /* "coam.co", true */ 'c', 'o', 'a', 'm', '.', 'c', 'o', '\0',
   /* "coatl-industries.com", true */ 'c', 'o', 'a', 't', 'l', '-', 'i', 'n', 'd', 'u', 's', 't', 'r', 'i', 'e', 's', '.', 'c', 'o', 'm', '\0',
   /* "cobalt.io", true */ 'c', 'o', 'b', 'a', 'l', 't', '.', 'i', 'o', '\0',
   /* "cobrasystems.nl", true */ 'c', 'o', 'b', 'r', 'a', 's', 'y', 's', 't', 'e', 'm', 's', '.', 'n', 'l', '\0',
@@ -2716,16 +2713,17 @@ static const char kSTSHostTable[] = {
   /* "codeforhakodate.org", true */ 'c', 'o', 'd', 'e', 'f', 'o', 'r', 'h', 'a', 'k', 'o', 'd', 'a', 't', 'e', '.', 'o', 'r', 'g', '\0',
   /* "codefoundry.it", false */ 'c', 'o', 'd', 'e', 'f', 'o', 'u', 'n', 'd', 'r', 'y', '.', 'i', 't', '\0',
   /* "codeit.guru", true */ 'c', 'o', 'd', 'e', 'i', 't', '.', 'g', 'u', 'r', 'u', '\0',
   /* "codelove.de", true */ 'c', 'o', 'd', 'e', 'l', 'o', 'v', 'e', '.', 'd', 'e', '\0',
   /* "codenode.io", true */ 'c', 'o', 'd', 'e', 'n', 'o', 'd', 'e', '.', 'i', 'o', '\0',
   /* "codeplay.org", true */ 'c', 'o', 'd', 'e', 'p', 'l', 'a', 'y', '.', 'o', 'r', 'g', '\0',
   /* "codepoints.net", true */ 'c', 'o', 'd', 'e', 'p', 'o', 'i', 'n', 't', 's', '.', 'n', 'e', 't', '\0',
   /* "codepref.com", true */ 'c', 'o', 'd', 'e', 'p', 'r', 'e', 'f', '.', 'c', 'o', 'm', '\0',
+  /* "codepult.com", true */ 'c', 'o', 'd', 'e', 'p', 'u', 'l', 't', '.', 'c', 'o', 'm', '\0',
   /* "codera.co.uk", true */ 'c', 'o', 'd', 'e', 'r', 'a', '.', 'c', 'o', '.', 'u', 'k', '\0',
   /* "codereview.appspot.com", false */ 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w', '.', 'a', 'p', 'p', 's', 'p', 'o', 't', '.', 'c', 'o', 'm', '\0',
   /* "codereview.chromium.org", false */ 'c', 'o', 'd', 'e', 'r', 'e', 'v', 'i', 'e', 'w', '.', 'c', 'h', 'r', 'o', 'm', 'i', 'u', 'm', '.', 'o', 'r', 'g', '\0',
   /* "coderhangout.com", true */ 'c', 'o', 'd', 'e', 'r', 'h', 'a', 'n', 'g', 'o', 'u', 't', '.', 'c', 'o', 'm', '\0',
   /* "codesport.io", true */ 'c', 'o', 'd', 'e', 's', 'p', 'o', 'r', 't', '.', 'i', 'o', '\0',
   /* "codeux.com", true */ 'c', 'o', 'd', 'e', 'u', 'x', '.', 'c', 'o', 'm', '\0',
   /* "codewild.de", true */ 'c', 'o', 'd', 'e', 'w', 'i', 'l', 'd', '.', 'd', 'e', '\0',
   /* "codewiz.xyz", true */ 'c', 'o', 'd', 'e', 'w', 'i', 'z', '.', 'x', 'y', 'z', '\0',
@@ -2901,16 +2899,17 @@ static const char kSTSHostTable[] = {
   /* "coredump.gr", true */ 'c', 'o', 'r', 'e', 'd', 'u', 'm', 'p', '.', 'g', 'r', '\0',
   /* "coreinfrastructure.org", true */ 'c', 'o', 'r', 'e', 'i', 'n', 'f', 'r', 'a', 's', 't', 'r', 'u', 'c', 't', 'u', 'r', 'e', '.', 'o', 'r', 'g', '\0',
   /* "coreless-stretchfilm.com", true */ 'c', 'o', 'r', 'e', 'l', 'e', 's', 's', '-', 's', 't', 'r', 'e', 't', 'c', 'h', 'f', 'i', 'l', 'm', '.', 'c', 'o', 'm', '\0',
   /* "corepartners.com.ua", true */ 'c', 'o', 'r', 'e', 'p', 'a', 'r', 't', 'n', 'e', 'r', 's', '.', 'c', 'o', 'm', '.', 'u', 'a', '\0',
   /* "coresolutions.ca", true */ 'c', 'o', 'r', 'e', 's', 'o', 'l', 'u', 't', 'i', 'o', 'n', 's', '.', 'c', 'a', '\0',
   /* "corex.io", true */ 'c', 'o', 'r', 'e', 'x', '.', 'i', 'o', '\0',
   /* "coreyjmahler.com", true */ 'c', 'o', 'r', 'e', 'y', 'j', 'm', 'a', 'h', 'l', 'e', 'r', '.', 'c', 'o', 'm', '\0',
   /* "corgi.party", true */ 'c', 'o', 'r', 'g', 'i', '.', 'p', 'a', 'r', 't', 'y', '\0',
+  /* "corgicloud.com", true */ 'c', 'o', 'r', 'g', 'i', 'c', 'l', 'o', 'u', 'd', '.', 'c', 'o', 'm', '\0',
   /* "cornercircle.co.uk", true */ 'c', 'o', 'r', 'n', 'e', 'r', 'c', 'i', 'r', 'c', 'l', 'e', '.', 'c', 'o', '.', 'u', 'k', '\0',
   /* "corniche.com", true */ 'c', 'o', 'r', 'n', 'i', 'c', 'h', 'e', '.', 'c', 'o', 'm', '\0',
   /* "cornishcamels.com", true */ 'c', 'o', 'r', 'n', 'i', 's', 'h', 'c', 'a', 'm', 'e', 'l', 's', '.', 'c', 'o', 'm', '\0',
   /* "cornodo.com", true */ 'c', 'o', 'r', 'n', 'o', 'd', 'o', '.', 'c', 'o', 'm', '\0',
   /* "corona-academy.com", true */ 'c', 'o', 'r', 'o', 'n', 'a', '-', 'a', 'c', 'a', 'd', 'e', 'm', 'y', '.', 'c', 'o', 'm', '\0',
   /* "coronelpicanha.com.br", true */ 'c', 'o', 'r', 'o', 'n', 'e', 'l', 'p', 'i', 'c', 'a', 'n', 'h', 'a', '.', 'c', 'o', 'm', '.', 'b', 'r', '\0',
   /* "corpfin.net", true */ 'c', 'o', 'r', 'p', 'f', 'i', 'n', '.', 'n', 'e', 't', '\0',
   /* "corporatesubscriptions.com.au", true */ 'c', 'o', 'r', 'p', 'o', 'r', 'a', 't', 'e', 's', 'u', 'b', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 's', '.', 'c', 'o', 'm', '.', 'a', 'u', '\0',
@@ -3025,16 +3024,17 @@ static const char kSTSHostTable[] = {
   /* "crustytoothpaste.net", true */ 'c', 'r', 'u', 's', 't', 'y', 't', 'o', 'o', 't', 'h', 'p', 'a', 's', 't', 'e', '.', 'n', 'e', 't', '\0',
   /* "crute.me", true */ 'c', 'r', 'u', 't', 'e', '.', 'm', 'e', '\0',
   /* "crvv.me", true */ 'c', 'r', 'v', 'v', '.', 'm', 'e', '\0',
   /* "cryptearth.de", true */ 'c', 'r', 'y', 'p', 't', 'e', 'a', 'r', 't', 'h', '.', 'd', 'e', '\0',
   /* "crypto.cat", false */ 'c', 'r', 'y', 'p', 't', 'o', '.', 'c', 'a', 't', '\0',
   /* "crypto.graphics", true */ 'c', 'r', 'y', 'p', 't', 'o', '.', 'g', 'r', 'a', 'p', 'h', 'i', 'c', 's', '\0',
   /* "crypto.is", false */ 'c', 'r', 'y', 'p', 't', 'o', '.', 'i', 's', '\0',
   /* "cryptobells.com", false */ 'c', 'r', 'y', 'p', 't', 'o', 'b', 'e', 'l', 'l', 's', '.', 'c', 'o', 'm', '\0',
+  /* "cryptobin.co", true */ 'c', 'r', 'y', 'p', 't', 'o', 'b', 'i', 'n', '.', 'c', 'o', '\0',
   /* "cryptocon.org", true */ 'c', 'r', 'y', 'p', 't', 'o', 'c', 'o', 'n', '.', 'o', 'r', 'g', '\0',
   /* "cryptodash.net", true */ 'c', 'r', 'y', 'p', 't', 'o', 'd', 'a', 's', 'h', '.', 'n', 'e', 't', '\0',
   /* "cryptography.io", true */ 'c', 'r', 'y', 'p', 't', 'o', 'g', 'r', 'a', 'p', 'h', 'y', '.', 'i', 'o', '\0',
   /* "cryptoisnotacrime.org", true */ 'c', 'r', 'y', 'p', 't', 'o', 'i', 's', 'n', 'o', 't', 'a', 'c', 'r', 'i', 'm', 'e', '.', 'o', 'r', 'g', '\0',
   /* "cryptonit.net", true */ 'c', 'r', 'y', 'p', 't', 'o', 'n', 'i', 't', '.', 'n', 'e', 't', '\0',
   /* "cryptonym.com", true */ 'c', 'r', 'y', 'p', 't', 'o', 'n', 'y', 'm', '.', 'c', 'o', 'm', '\0',
   /* "cryptoparty.at", true */ 'c', 'r', 'y', 'p', 't', 'o', 'p', 'a', 'r', 't', 'y', '.', 'a', 't', '\0',
   /* "cryptoparty.dk", true */ 'c', 'r', 'y', 'p', 't', 'o', 'p', 'a', 'r', 't', 'y', '.', 'd', 'k', '\0',
@@ -3420,17 +3420,16 @@ static const char kSTSHostTable[] = {
   /* "dee.pe", true */ 'd', 'e', 'e', '.', 'p', 'e', '\0',
   /* "deepbluecrafting.co.uk", true */ 'd', 'e', 'e', 'p', 'b', 'l', 'u', 'e', 'c', 'r', 'a', 'f', 't', 'i', 'n', 'g', '.', 'c', 'o', '.', 'u', 'k', '\0',
   /* "deeprecce.com", true */ 'd', 'e', 'e', 'p', 'r', 'e', 'c', 'c', 'e', '.', 'c', 'o', 'm', '\0',
   /* "deeprecce.link", true */ 'd', 'e', 'e', 'p', 'r', 'e', 'c', 'c', 'e', '.', 'l', 'i', 'n', 'k', '\0',
   /* "deeprecce.tech", true */ 'd', 'e', 'e', 'p', 'r', 'e', 'c', 'c', 'e', '.', 't', 'e', 'c', 'h', '\0',
   /* "deepserve.info", true */ 'd', 'e', 'e', 'p', 's', 'e', 'r', 'v', 'e', '.', 'i', 'n', 'f', 'o', '\0',
   /* "deepzz.com", true */ 'd', 'e', 'e', 'p', 'z', 'z', '.', 'c', 'o', 'm', '\0',
   /* "deer.team", true */ 'd', 'e', 'e', 'r', '.', 't', 'e', 'a', 'm', '\0',
-  /* "deetz.nl", true */ 'd', 'e', 'e', 't', 'z', '.', 'n', 'l', '\0',
   /* "deezeno.com", true */ 'd', 'e', 'e', 'z', 'e', 'n', 'o', '.', 'c', 'o', 'm', '\0',
   /* "def-pos.ru", true */ 'd', 'e', 'f', '-', 'p', 'o', 's', '.', 'r', 'u', '\0',
   /* "defcon.org", true */ 'd', 'e', 'f', 'c', 'o', 'n', '.', 'o', 'r', 'g', '\0',
   /* "defendas.com", true */ 'd', 'e', 'f', 'e', 'n', 'd', 'a', 's', '.', 'c', 'o', 'm', '\0',
   /* "defero.io", true */ 'd', 'e', 'f', 'e', 'r', 'o', '.', 'i', 'o', '\0',
   /* "defi-metier.com", true */ 'd', 'e', 'f', 'i', '-', 'm', 'e', 't', 'i', 'e', 'r', '.', 'c', 'o', 'm', '\0',
   /* "defi-metier.fr", true */ 'd', 'e', 'f', 'i', '-', 'm', 'e', 't', 'i', 'e', 'r', '.', 'f', 'r', '\0',
   /* "defi-metier.org", true */ 'd', 'e', 'f', 'i', '-', 'm', 'e', 't', 'i', 'e', 'r', '.', 'o', 'r', 'g', '\0',
@@ -3581,16 +3580,17 @@ static const char kSTSHostTable[] = {
   /* "dgt-portal.de", true */ 'd', 'g', 't', '-', 'p', 'o', 'r', 't', 'a', 'l', '.', 'd', 'e', '\0',
   /* "dhautefeuille.eu", true */ 'd', 'h', 'a', 'u', 't', 'e', 'f', 'e', 'u', 'i', 'l', 'l', 'e', '.', 'e', 'u', '\0',
   /* "dhauwer.nl", true */ 'd', 'h', 'a', 'u', 'w', 'e', 'r', '.', 'n', 'l', '\0',
   /* "dhedegaard.dk", true */ 'd', 'h', 'e', 'd', 'e', 'g', 'a', 'a', 'r', 'd', '.', 'd', 'k', '\0',
   /* "dhhs.gov", true */ 'd', 'h', 'h', 's', '.', 'g', 'o', 'v', '\0',
   /* "dhome.at", true */ 'd', 'h', 'o', 'm', 'e', '.', 'a', 't', '\0',
   /* "dhuy.net", true */ 'd', 'h', 'u', 'y', '.', 'n', 'e', 't', '\0',
   /* "diagnostix.org", true */ 'd', 'i', 'a', 'g', 'n', 'o', 's', 't', 'i', 'x', '.', 'o', 'r', 'g', '\0',
+  /* "diamante.ro", true */ 'd', 'i', 'a', 'm', 'a', 'n', 't', 'e', '.', 'r', 'o', '\0',
   /* "dianefriedli.ch", true */ 'd', 'i', 'a', 'n', 'e', 'f', 'r', 'i', 'e', 'd', 'l', 'i', '.', 'c', 'h', '\0',
   /* "dianlujitao.com", true */ 'd', 'i', 'a', 'n', 'l', 'u', 'j', 'i', 't', 'a', 'o', '.', 'c', 'o', 'm', '\0',
   /* "diare-na-miru.cz", true */ 'd', 'i', 'a', 'r', 'e', '-', 'n', 'a', '-', 'm', 'i', 'r', 'u', '.', 'c', 'z', '\0',
   /* "diasdasemana.com", true */ 'd', 'i', 'a', 's', 'd', 'a', 's', 'e', 'm', 'a', 'n', 'a', '.', 'c', 'o', 'm', '\0',
   /* "diasp.org", true */ 'd', 'i', 'a', 's', 'p', '.', 'o', 'r', 'g', '\0',
   /* "diasporadialogues.com", true */ 'd', 'i', 'a', 's', 'p', 'o', 'r', 'a', 'd', 'i', 'a', 'l', 'o', 'g', 'u', 'e', 's', '.', 'c', 'o', 'm', '\0',
   /* "diavo.de", true */ 'd', 'i', 'a', 'v', 'o', '.', 'd', 'e', '\0',
   /* "dibiphp.com", true */ 'd', 'i', 'b', 'i', 'p', 'h', 'p', '.', 'c', 'o', 'm', '\0',
@@ -3711,17 +3711,16 @@ static const char kSTSHostTable[] = {
   /* "divingwithnic.com", true */ 'd', 'i', 'v', 'i', 'n', 'g', 'w', 'i', 't', 'h', 'n', 'i', 'c', '.', 'c', 'o', 'm', '\0',
   /* "dixiediner.com", true */ 'd', 'i', 'x', 'i', 'e', 'd', 'i', 'n', 'e', 'r', '.', 'c', 'o', 'm', '\0',
   /* "dixmag.com", true */ 'd', 'i', 'x', 'm', 'a', 'g', '.', 'c', 'o', 'm', '\0',
   /* "diybook.at", true */ 'd', 'i', 'y', 'b', 'o', 'o', 'k', '.', 'a', 't', '\0',
   /* "diycc.org", true */ 'd', 'i', 'y', 'c', 'c', '.', 'o', 'r', 'g', '\0',
   /* "djangoproject.com", true */ 'd', 'j', 'a', 'n', 'g', 'o', 'p', 'r', 'o', 'j', 'e', 'c', 't', '.', 'c', 'o', 'm', '\0',
   /* "djangosnippets.org", true */ 'd', 'j', 'a', 'n', 'g', 'o', 's', 'n', 'i', 'p', 'p', 'e', 't', 's', '.', 'o', 'r', 'g', '\0',
   /* "djlive.pl", true */ 'd', 'j', 'l', 'i', 'v', 'e', '.', 'p', 'l', '\0',
-  /* "djlnetworks.co.uk", true */ 'd', 'j', 'l', 'n', 'e', 't', 'w', 'o', 'r', 'k', 's', '.', 'c', 'o', '.', 'u', 'k', '\0',
   /* "djul.net", true */ 'd', 'j', 'u', 'l', '.', 'n', 'e', 't', '\0',
   /* "djxmmx.net", false */ 'd', 'j', 'x', 'm', 'm', 'x', '.', 'n', 'e', 't', '\0',
   /* "dk.search.yahoo.com", false */ 'd', 'k', '.', 's', 'e', 'a', 'r', 'c', 'h', '.', 'y', 'a', 'h', 'o', 'o', '.', 'c', 'o', 'm', '\0',
   /* "dkds.us", true */ 'd', 'k', 'd', 's', '.', 'u', 's', '\0',
   /* "dkravchenko.su", true */ 'd', 'k', 'r', 'a', 'v', 'c', 'h', 'e', 'n', 'k', 'o', '.', 's', 'u', '\0',
   /* "dl.google.com", true */ 'd', 'l', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm', '\0',
   /* "dlaspania.pl", true */ 'd', 'l', 'a', 's', 'p', 'a', 'n', 'i', 'a', '.', 'p', 'l', '\0',
   /* "dlitz.net", true */ 'd', 'l', 'i', 't', 'z', '.', 'n', 'e', 't', '\0',
@@ -3864,29 +3863,26 @@ static const char kSTSHostTable[] = {
   /* "dounats.com", true */ 'd', 'o', 'u', 'n', 'a', 't', 's', '.', 'c', 'o', 'm', '\0',
   /* "downloadaja.com", true */ 'd', 'o', 'w', 'n', 'l', 'o', 'a', 'd', 'a', 'j', 'a', '.', 'c', 'o', 'm', '\0',
   /* "downloadgamemods.com", true */ 'd', 'o', 'w', 'n', 'l', 'o', 'a', 'd', 'g', 'a', 'm', 'e', 'm', 'o', 'd', 's', '.', 'c', 'o', 'm', '\0',
   /* "downloadgram.com", true */ 'd', 'o', 'w', 'n', 'l', 'o', 'a', 'd', 'g', 'r', 'a', 'm', '.', 'c', 'o', 'm', '\0',
   /* "downloadsoftwaregratisan.com", true */ 'd', 'o', 'w', 'n', 'l', 'o', 'a', 'd', 's', 'o', 'f', 't', 'w', 'a', 'r', 'e', 'g', 'r', 'a', 't', 'i', 's', 'a', 'n', '.', 'c', 'o', 'm', '\0',
   /* "doyoulyft.com", true */ 'd', 'o', 'y', 'o', 'u', 'l', 'y', 'f', 't', '.', 'c', 'o', 'm', '\0',
   /* "dpd.com.pl", true */ 'd', 'p', 'd', '.', 'c', 'o', 'm', '.', 'p', 'l', '\0',
   /* "dprd-wonogirikab.go.id", false */ 'd', 'p', 'r', 'd', '-', 'w', 'o', 'n', 'o', 'g', 'i', 'r', 'i', 'k', 'a', 'b', '.', 'g', 'o', '.', 'i', 'd', '\0',
-  /* "dpsg-roden.de", false */ 'd', 'p', 's', 'g', '-', 'r', 'o', 'd', 'e', 'n', '.', 'd', 'e', '\0',
   /* "dr2dr.ca", true */ 'd', 'r', '2', 'd', 'r', '.', 'c', 'a', '\0',
   /* "dragfiles.com", true */ 'd', 'r', 'a', 'g', 'f', 'i', 'l', 'e', 's', '.', 'c', 'o', 'm', '\0',
   /* "dragon-aspect.com", true */ 'd', 'r', 'a', 'g', 'o', 'n', '-', 'a', 's', 'p', 'e', 'c', 't', '.', 'c', 'o', 'm', '\0',
   /* "dragon-chem.eu", true */ 'd', 'r', 'a', 'g', 'o', 'n', '-', 'c', 'h', 'e', 'm', '.', 'e', 'u', '\0',
   /* "dragonfly.co.uk", true */ 'd', 'r', 'a', 'g', 'o', 'n', 'f', 'l', 'y', '.', 'c', 'o', '.', 'u', 'k', '\0',
   /* "dragonschool.org", true */ 'd', 'r', 'a', 'g', 'o', 'n', 's', 'c', 'h', 'o', 'o', 'l', '.', 'o', 'r', 'g', '\0',
   /* "dragonstower.net", true */ 'd', 'r', 'a', 'g', 'o', 'n', 's', 't', 'o', 'w', 'e', 'r', '.', 'n', 'e', 't', '\0',
   /* "dragonteam.ninja", true */ 'd', 'r', 'a', 'g', 'o', 'n', 't', 'e', 'a', 'm', '.', 'n', 'i', 'n', 'j', 'a', '\0',
   /* "drahcro.uk", true */ 'd', 'r', 'a', 'h', 'c', 'r', 'o', '.', 'u', 'k', '\0',
   /* "drainagebuizen.nl", true */ 'd', 'r', 'a', 'i', 'n', 'a', 'g', 'e', 'b', 'u', 'i', 'z', 'e', 'n', '.', 'n', 'l', '\0',
-  /* "drakeanddragon.com", true */ 'd', 'r', 'a', 'k', 'e', 'a', 'n', 'd', 'd', 'r', 'a', 'g', 'o', 'n', '.', 'c', 'o', 'm', '\0',
-  /* "drakefortreasurer.sexy", true */ 'd', 'r', 'a', 'k', 'e', 'f', 'o', 'r', 't', 'r', 'e', 'a', 's', 'u', 'r', 'e', 'r', '.', 's', 'e', 'x', 'y', '\0',
   /* "drakeluce.com", true */ 'd', 'r', 'a', 'k', 'e', 'l', 'u', 'c', 'e', '.', 'c', 'o', 'm', '\0',
   /* "drakenprospero.com", true */ 'd', 'r', 'a', 'k', 'e', 'n', 'p', 'r', 'o', 's', 'p', 'e', 'r', 'o', '.', 'c', 'o', 'm', '\0',
   /* "dramaticpeople.com", true */ 'd', 'r', 'a', 'm', 'a', 't', 'i', 'c', 'p', 'e', 'o', 'p', 'l', 'e', '.', 'c', 'o', 'm', '\0',
   /* "dranderle.com", true */ 'd', 'r', 'a', 'n', 'd', 'e', 'r', 'l', 'e', '.', 'c', 'o', 'm', '\0',
   /* "dranek.com", true */ 'd', 'r', 'a', 'n', 'e', 'k', '.', 'c', 'o', 'm', '\0',
   /* "draugr.de", true */ 'd', 'r', 'a', 'u', 'g', 'r', '.', 'd', 'e', '\0',
   /* "drawesome.uy", true */ 'd', 'r', 'a', 'w', 'e', 's', 'o', 'm', 'e', '.', 'u', 'y', '\0',
   /* "drawingcode.net", true */ 'd', 'r', 'a', 'w', 'i', 'n', 'g', 'c', 'o', 'd', 'e', '.', 'n', 'e', 't', '\0',
@@ -3981,44 +3977,45 @@ static const char kSTSHostTable[] = {
   /* "dungi.org", true */ 'd', 'u', 'n', 'g', 'i', '.', 'o', 'r', 'g', '\0',
   /* "duo.money", true */ 'd', 'u', 'o', '.', 'm', 'o', 'n', 'e', 'y', '\0',
   /* "duoluodeyu.com", true */ 'd', 'u', 'o', 'l', 'u', 'o', 'd', 'e', 'y', 'u', '.', 'c', 'o', 'm', '\0',
   /* "dupree.co", true */ 'd', 'u', 'p', 'r', 'e', 'e', '.', 'c', 'o', '\0',
   /* "durangoenergyllc.com", true */ 'd', 'u', 'r', 'a', 'n', 'g', 'o', 'e', 'n', 'e', 'r', 'g', 'y', 'l', 'l', 'c', '.', 'c', 'o', 'm', '\0',
   /* "durys.be", true */ 'd', 'u', 'r', 'y', 's', '.', 'b', 'e', '\0',
   /* "dustygroove.com", true */ 'd', 'u', 's', 't', 'y', 'g', 'r', 'o', 'o', 'v', 'e', '.', 'c', 'o', 'm', '\0',
   /* "dutch1.nl", true */ 'd', 'u', 't', 'c', 'h', '1', '.', 'n', 'l', '\0',
+  /* "dutchessuganda.com", true */ 'd', 'u', 't', 'c', 'h', 'e', 's', 's', 'u', 'g', 'a', 'n', 'd', 'a', '.', 'c', 'o', 'm', '\0',
   /* "dutchrank.nl", true */ 'd', 'u', 't', 'c', 'h', 'r', 'a', 'n', 'k', '.', 'n', 'l', '\0',
   /* "dutchwanderers.nl", true */ 'd', 'u', 't', 'c', 'h', 'w', 'a', 'n', 'd', 'e', 'r', 'e', 'r', 's', '.', 'n', 'l', '\0',
   /* "dutchweballiance.nl", true */ 'd', 'u', 't', 'c', 'h', 'w', 'e', 'b', 'a', 'l', 'l', 'i', 'a', 'n', 'c', 'e', '.', 'n', 'l', '\0',
   /* "dutyfreeonboard.com", true */ 'd', 'u', 't', 'y', 'f', 'r', 'e', 'e', 'o', 'n', 'b', 'o', 'a', 'r', 'd', '.', 'c', 'o', 'm', '\0',
   /* "duuu.ch", true */ 'd', 'u', 'u', 'u', '.', 'c', 'h', '\0',
   /* "dvbris.co.uk", true */ 'd', 'v', 'b', 'r', 'i', 's', '.', 'c', 'o', '.', 'u', 'k', '\0',
   /* "dvbris.com", true */ 'd', 'v', 'b', 'r', 'i', 's', '.', 'c', 'o', 'm', '\0',
   /* "dvorupotocnych.sk", true */ 'd', 'v', 'o', 'r', 'u', 'p', 'o', 't', 'o', 'c', 'n', 'y', 'c', 'h', '.', 's', 'k', '\0',
   /* "dvotx.org", true */ 'd', 'v', 'o', 't', 'x', '.', 'o', 'r', 'g', '\0',
   /* "dvwc.org", true */ 'd', 'v', 'w', 'c', '.', 'o', 'r', 'g', '\0',
   /* "dwnld.me", true */ 'd', 'w', 'n', 'l', 'd', '.', 'm', 'e', '\0',
   /* "dwtm.ch", true */ 'd', 'w', 't', 'm', '.', 'c', 'h', '\0',
   /* "dxa.io", false */ 'd', 'x', 'a', '.', 'i', 'o', '\0',
   /* "dxgl.info", true */ 'd', 'x', 'g', 'l', '.', 'i', 'n', 'f', 'o', '\0',
   /* "dyeager.org", true */ 'd', 'y', 'e', 'a', 'g', 'e', 'r', '.', 'o', 'r', 'g', '\0',
   /* "dyktig.as", true */ 'd', 'y', 'k', 't', 'i', 'g', '.', 'a', 's', '\0',
-  /* "dymersion.com", true */ 'd', 'y', 'm', 'e', 'r', 's', 'i', 'o', 'n', '.', 'c', 'o', 'm', '\0',
   /* "dyn-nserve.net", true */ 'd', 'y', 'n', '-', 'n', 's', 'e', 'r', 'v', 'e', '.', 'n', 'e', 't', '\0',
   /* "dyn.im", true */ 'd', 'y', 'n', '.', 'i', 'm', '\0',
   /* "dynaloop.net", true */ 'd', 'y', 'n', 'a', 'l', 'o', 'o', 'p', '.', 'n', 'e', 't', '\0',
   /* "dynamicnet.net", false */ 'd', 'y', 'n', 'a', 'm', 'i', 'c', 'n', 'e', 't', '.', 'n', 'e', 't', '\0',
   /* "dynamicsnetwork.net", true */ 'd', 'y', 'n', 'a', 'm', 'i', 'c', 's', 'n', 'e', 't', 'w', 'o', 'r', 'k', '.', 'n', 'e', 't', '\0',
   /* "dynamictostatic.com", true */ 'd', 'y', 'n', 'a', 'm', 'i', 'c', 't', 'o', 's', 't', 'a', 't', 'i', 'c', '.', 'c', 'o', 'm', '\0',
   /* "dynamize.solutions", true */ 'd', 'y', 'n', 'a', 'm', 'i', 'z', 'e', '.', 's', 'o', 'l', 'u', 't', 'i', 'o', 'n', 's', '\0',
   /* "dyrenesverden.no", true */ 'd', 'y', 'r', 'e', 'n', 'e', 's', 'v', 'e', 'r', 'd', 'e', 'n', '.', 'n', 'o', '\0',
   /* "dyrkar.com", true */ 'd', 'y', 'r', 'k', 'a', 'r', '.', 'c', 'o', 'm', '\0',
   /* "dziekonski.com", true */ 'd', 'z', 'i', 'e', 'k', 'o', 'n', 's', 'k', 'i', '.', 'c', 'o', 'm', '\0',
   /* "dzndk.com", true */ 'd', 'z', 'n', 'd', 'k', '.', 'c', 'o', 'm', '\0',
+  /* "dzndk.net", true */ 'd', 'z', 'n', 'd', 'k', '.', 'n', 'e', 't', '\0',
   /* "dzyabchenko.com", true */ 'd', 'z', 'y', 'a', 'b', 'c', 'h', 'e', 'n', 'k', 'o', '.', 'c', 'o', 'm', '\0',
   /* "e-biografias.net", true */ 'e', '-', 'b', 'i', 'o', 'g', 'r', 'a', 'f', 'i', 'a', 's', '.', 'n', 'e', 't', '\0',
   /* "e-isfa.eu", true */ 'e', '-', 'i', 's', 'f', 'a', '.', 'e', 'u', '\0',
   /* "e-kontakti.fi", true */ 'e', '-', 'k', 'o', 'n', 't', 'a', 'k', 't', 'i', '.', 'f', 'i', '\0',
   /* "e-learningbs.com", true */ 'e', '-', 'l', 'e', 'a', 'r', 'n', 'i', 'n', 'g', 'b', 's', '.', 'c', 'o', 'm', '\0',
   /* "e-lifetechnology.com", true */ 'e', '-', 'l', 'i', 'f', 'e', 't', 'e', 'c', 'h', 'n', 'o', 'l', 'o', 'g', 'y', '.', 'c', 'o', 'm', '\0',
   /* "e-mak.eu", true */ 'e', '-', 'm', 'a', 'k', '.', 'e', 'u', '\0',
   /* "e-rickroll-r.pw", true */ 'e', '-', 'r', 'i', 'c', 'k', 'r', 'o', 'l', 'l', '-', 'r', '.', 'p', 'w', '\0',
@@ -4216,17 +4213,16 @@ static const char kSTSHostTable[] = {
   /* "electricant.com", true */ 'e', 'l', 'e', 'c', 't', 'r', 'i', 'c', 'a', 'n', 't', '.', 'c', 'o', 'm', '\0',
   /* "electricant.nl", true */ 'e', 'l', 'e', 'c', 't', 'r', 'i', 'c', 'a', 'n', 't', '.', 'n', 'l', '\0',
   /* "electricoperaduo.com", true */ 'e', 'l', 'e', 'c', 't', 'r', 'i', 'c', 'o', 'p', 'e', 'r', 'a', 'd', 'u', 'o', '.', 'c', 'o', 'm', '\0',
   /* "electronic-ignition-system.com", true */ 'e', 'l', 'e', 'c', 't', 'r', 'o', 'n', 'i', 'c', '-', 'i', 'g', 'n', 'i', 't', 'i', 'o', 'n', '-', 's', 'y', 's', 't', 'e', 'm', '.', 'c', 'o', 'm', '\0',
   /* "electronicfasteners.com", true */ 'e', 'l', 'e', 'c', 't', 'r', 'o', 'n', 'i', 'c', 'f', 'a', 's', 't', 'e', 'n', 'e', 'r', 's', '.', 'c', 'o', 'm', '\0',
   /* "elefantevoador.com", true */ 'e', 'l', 'e', 'f', 'a', 'n', 't', 'e', 'v', 'o', 'a', 'd', 'o', 'r', '.', 'c', 'o', 'm', '\0',
   /* "eleicoes2016.com.br", true */ 'e', 'l', 'e', 'i', 'c', 'o', 'e', 's', '2', '0', '1', '6', '.', 'c', 'o', 'm', '.', 'b', 'r', '\0',
   /* "elektro-koehl.de", true */ 'e', 'l', 'e', 'k', 't', 'r', 'o', '-', 'k', 'o', 'e', 'h', 'l', '.', 'd', 'e', '\0',
-  /* "elektronring.com", true */ 'e', 'l', 'e', 'k', 't', 'r', 'o', 'n', 'r', 'i', 'n', 'g', '.', 'c', 'o', 'm', '\0',
   /* "elektropost.org", true */ 'e', 'l', 'e', 'k', 't', 'r', 'o', 'p', 'o', 's', 't', '.', 'o', 'r', 'g', '\0',
   /* "element-43.com", true */ 'e', 'l', 'e', 'm', 'e', 'n', 't', '-', '4', '3', '.', 'c', 'o', 'm', '\0',
   /* "elemental.software", true */ 'e', 'l', 'e', 'm', 'e', 'n', 't', 'a', 'l', '.', 's', 'o', 'f', 't', 'w', 'a', 'r', 'e', '\0',
   /* "elementalrobotics.com", true */ 'e', 'l', 'e', 'm', 'e', 'n', 't', 'a', 'l', 'r', 'o', 'b', 'o', 't', 'i', 'c', 's', '.', 'c', 'o', 'm', '\0',
   /* "elementalsoftware.net", true */ 'e', 'l', 'e', 'm', 'e', 'n', 't', 'a', 'l', 's', 'o', 'f', 't', 'w', 'a', 'r', 'e', '.', 'n', 'e', 't', '\0',
   /* "elementalsoftware.org", true */ 'e', 'l', 'e', 'm', 'e', 'n', 't', 'a', 'l', 's', 'o', 'f', 't', 'w', 'a', 'r', 'e', '.', 'o', 'r', 'g', '\0',
   /* "elena-baykova.ru", true */ 'e', 'l', 'e', 'n', 'a', '-', 'b', 'a', 'y', 'k', 'o', 'v', 'a', '.', 'r', 'u', '\0',
   /* "elenagherta.ga", true */ 'e', 'l', 'e', 'n', 'a', 'g', 'h', 'e', 'r', 't', 'a', '.', 'g', 'a', '\0',
@@ -4300,16 +4296,17 @@ static const char kSTSHostTable[] = {
   /* "encfs.win", true */ 'e', 'n', 'c', 'f', 's', '.', 'w', 'i', 'n', '\0',
   /* "encircleapp.com", true */ 'e', 'n', 'c', 'i', 'r', 'c', 'l', 'e', 'a', 'p', 'p', '.', 'c', 'o', 'm', '\0',
   /* "encnet.de", true */ 'e', 'n', 'c', 'n', 'e', 't', '.', 'd', 'e', '\0',
   /* "encode.uk.com", true */ 'e', 'n', 'c', 'o', 'd', 'e', '.', 'u', 'k', '.', 'c', 'o', 'm', '\0',
   /* "encredible.de", false */ 'e', 'n', 'c', 'r', 'e', 'd', 'i', 'b', 'l', 'e', '.', 'd', 'e', '\0',
   /* "encredible.org", false */ 'e', 'n', 'c', 'r', 'e', 'd', 'i', 'b', 'l', 'e', '.', 'o', 'r', 'g', '\0',
   /* "encryptallthethings.net", true */ 'e', 'n', 'c', 'r', 'y', 'p', 't', 'a', 'l', 'l', 't', 'h', 'e', 't', 'h', 'i', 'n', 'g', 's', '.', 'n', 'e', 't', '\0',
   /* "encrypted.google.com", true */ 'e', 'n', 'c', 'r', 'y', 'p', 't', 'e', 'd', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm', '\0',
+  /* "encryptedaudience.com", true */ 'e', 'n', 'c', 'r', 'y', 'p', 't', 'e', 'd', 'a', 'u', 'd', 'i', 'e', 'n', 'c', 'e', '.', 'c', 'o', 'm', '\0',
   /* "encryptio.com", true */ 'e', 'n', 'c', 'r', 'y', 'p', 't', 'i', 'o', '.', 'c', 'o', 'm', '\0',
   /* "endeal.nl", true */ 'e', 'n', 'd', 'e', 'a', 'l', '.', 'n', 'l', '\0',
   /* "ender.co.at", true */ 'e', 'n', 'd', 'e', 'r', '.', 'c', 'o', '.', 'a', 't', '\0',
   /* "endlesshorizon.net", true */ 'e', 'n', 'd', 'l', 'e', 's', 's', 'h', 'o', 'r', 'i', 'z', 'o', 'n', '.', 'n', 'e', 't', '\0',
   /* "endlessvideo.com", true */ 'e', 'n', 'd', 'l', 'e', 's', 's', 'v', 'i', 'd', 'e', 'o', '.', 'c', 'o', 'm', '\0',
   /* "endofnet.org", true */ 'e', 'n', 'd', 'o', 'f', 'n', 'e', 't', '.', 'o', 'r', 'g', '\0',
   /* "endohaus.ca", true */ 'e', 'n', 'd', 'o', 'h', 'a', 'u', 's', '.', 'c', 'a', '\0',
   /* "endohaus.com", true */ 'e', 'n', 'd', 'o', 'h', 'a', 'u', 's', '.', 'c', 'o', 'm', '\0',
@@ -4405,16 +4402,17 @@ static const char kSTSHostTable[] =