Bug 1335525 - Add top-level webrender crates to gfx/. r=gfx
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 06 Feb 2017 11:42:52 -0500
changeset 479447 bafbb19be9a460d896e0d065843e5507610b6171
parent 479417 7f1b358fb17dfd982c5e18c34d5735cd481c7f7c
child 479448 7fa68c2685b2d3fe239e7118a55aae852e56beed
push id44263
push userbmo:madeleinechercover@me.com
push dateMon, 06 Feb 2017 18:53:13 +0000
reviewersgfx
bugs1335525
milestone54.0a1
Bug 1335525 - Add top-level webrender crates to gfx/. r=gfx MozReview-Commit-ID: BXVNHlczLh5
gfx/webrender/Cargo.toml
gfx/webrender/build.rs
gfx/webrender/res/clip_shared.glsl
gfx/webrender/res/cs_blur.fs.glsl
gfx/webrender/res/cs_blur.glsl
gfx/webrender/res/cs_blur.vs.glsl
gfx/webrender/res/cs_box_shadow.fs.glsl
gfx/webrender/res/cs_box_shadow.glsl
gfx/webrender/res/cs_box_shadow.vs.glsl
gfx/webrender/res/cs_clip_image.fs.glsl
gfx/webrender/res/cs_clip_image.glsl
gfx/webrender/res/cs_clip_image.vs.glsl
gfx/webrender/res/cs_clip_rectangle.fs.glsl
gfx/webrender/res/cs_clip_rectangle.glsl
gfx/webrender/res/cs_clip_rectangle.vs.glsl
gfx/webrender/res/cs_text_run.fs.glsl
gfx/webrender/res/cs_text_run.glsl
gfx/webrender/res/cs_text_run.vs.glsl
gfx/webrender/res/debug_color.fs.glsl
gfx/webrender/res/debug_color.vs.glsl
gfx/webrender/res/debug_font.fs.glsl
gfx/webrender/res/debug_font.vs.glsl
gfx/webrender/res/prim_shared.glsl
gfx/webrender/res/ps_angle_gradient.fs.glsl
gfx/webrender/res/ps_angle_gradient.glsl
gfx/webrender/res/ps_angle_gradient.vs.glsl
gfx/webrender/res/ps_blend.fs.glsl
gfx/webrender/res/ps_blend.glsl
gfx/webrender/res/ps_blend.vs.glsl
gfx/webrender/res/ps_border.fs.glsl
gfx/webrender/res/ps_border.glsl
gfx/webrender/res/ps_border.vs.glsl
gfx/webrender/res/ps_box_shadow.fs.glsl
gfx/webrender/res/ps_box_shadow.glsl
gfx/webrender/res/ps_box_shadow.vs.glsl
gfx/webrender/res/ps_cache_image.fs.glsl
gfx/webrender/res/ps_cache_image.glsl
gfx/webrender/res/ps_cache_image.vs.glsl
gfx/webrender/res/ps_clear.fs.glsl
gfx/webrender/res/ps_clear.glsl
gfx/webrender/res/ps_clear.vs.glsl
gfx/webrender/res/ps_composite.fs.glsl
gfx/webrender/res/ps_composite.glsl
gfx/webrender/res/ps_composite.vs.glsl
gfx/webrender/res/ps_gradient.fs.glsl
gfx/webrender/res/ps_gradient.glsl
gfx/webrender/res/ps_gradient.vs.glsl
gfx/webrender/res/ps_image.fs.glsl
gfx/webrender/res/ps_image.glsl
gfx/webrender/res/ps_image.vs.glsl
gfx/webrender/res/ps_radial_gradient.fs.glsl
gfx/webrender/res/ps_radial_gradient.glsl
gfx/webrender/res/ps_radial_gradient.vs.glsl
gfx/webrender/res/ps_rectangle.fs.glsl
gfx/webrender/res/ps_rectangle.glsl
gfx/webrender/res/ps_rectangle.vs.glsl
gfx/webrender/res/ps_text_run.fs.glsl
gfx/webrender/res/ps_text_run.glsl
gfx/webrender/res/ps_text_run.vs.glsl
gfx/webrender/res/ps_yuv_image.fs.glsl
gfx/webrender/res/ps_yuv_image.glsl
gfx/webrender/res/ps_yuv_image.vs.glsl
gfx/webrender/res/shared.glsl
gfx/webrender/res/shared_other.glsl
gfx/webrender/src/batch_builder.rs
gfx/webrender/src/debug_colors.rs
gfx/webrender/src/debug_font_data.rs
gfx/webrender/src/debug_render.rs
gfx/webrender/src/device.rs
gfx/webrender/src/frame.rs
gfx/webrender/src/freelist.rs
gfx/webrender/src/geometry.rs
gfx/webrender/src/gpu_store.rs
gfx/webrender/src/internal_types.rs
gfx/webrender/src/layer.rs
gfx/webrender/src/lib.rs
gfx/webrender/src/mask_cache.rs
gfx/webrender/src/platform/macos/font.rs
gfx/webrender/src/platform/unix/font.rs
gfx/webrender/src/platform/windows/font.rs
gfx/webrender/src/prim_store.rs
gfx/webrender/src/profiler.rs
gfx/webrender/src/record.rs
gfx/webrender/src/render_backend.rs
gfx/webrender/src/renderer.rs
gfx/webrender/src/resource_cache.rs
gfx/webrender/src/scene.rs
gfx/webrender/src/scroll_tree.rs
gfx/webrender/src/spring.rs
gfx/webrender/src/texture_cache.rs
gfx/webrender/src/tiling.rs
gfx/webrender/src/util.rs
gfx/webrender/tests/angle_shader_validation.rs
gfx/webrender/tests/bug_124.html
gfx/webrender/tests/bug_134.html
gfx/webrender/tests/bug_137.html
gfx/webrender/tests/bug_143.html
gfx/webrender/tests/bug_159.html
gfx/webrender/tests/bug_166.html
gfx/webrender/tests/bug_176.html
gfx/webrender/tests/bug_177.html
gfx/webrender/tests/bug_178.html
gfx/webrender/tests/bug_203a.html
gfx/webrender/tests/bug_203b.html
gfx/webrender/tests/bug_servo_10136.html
gfx/webrender/tests/bug_servo_10164.html
gfx/webrender/tests/bug_servo_10307.html
gfx/webrender/tests/bug_servo_11358.html
gfx/webrender/tests/bug_servo_9983a.html
gfx/webrender/tests/color_pattern_1.png
gfx/webrender/tests/color_pattern_2.png
gfx/webrender/tests/fixed-position.html
gfx/webrender/tests/mix-blend-mode-2.html
gfx/webrender/tests/mix-blend-mode.html
gfx/webrender/tests/nav-1.html
gfx/webrender/tests/nav-2.html
gfx/webrender_bindings/Cargo.toml
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/src/lib.rs
gfx/webrender_traits/Cargo.toml
gfx/webrender_traits/build.rs
gfx/webrender_traits/src/api.rs
gfx/webrender_traits/src/channel.rs
gfx/webrender_traits/src/channel_ipc.rs
gfx/webrender_traits/src/channel_mpsc.rs
gfx/webrender_traits/src/display_item.rs
gfx/webrender_traits/src/display_list.rs
gfx/webrender_traits/src/lib.rs
gfx/webrender_traits/src/stacking_context.rs
gfx/webrender_traits/src/types.rs
gfx/webrender_traits/src/units.rs
gfx/webrender_traits/src/webgl.rs
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/Cargo.toml
@@ -0,0 +1,44 @@
+[package]
+name = "webrender"
+version = "0.11.1"
+authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
+license = "MPL-2.0"
+repository = "https://github.com/servo/webrender"
+build = "build.rs"
+workspace = ".."
+
+[features]
+default = ["codegen", "freetype-lib"]
+codegen = ["webrender_traits/codegen"]
+freetype-lib = ["freetype/servo-freetype-sys"]
+serde_derive = ["webrender_traits/serde_derive"]
+
+[dependencies]
+app_units = "0.3"
+bincode = "0.6"
+bit-set = "0.4"
+byteorder = "0.5"
+euclid = "0.10.3"
+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"]}
+time = "0.1"
+threadpool = "1.3.2"
+webrender_traits = {path = "../webrender_traits", default-features = false}
+bitflags = "0.7"
+
+[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.5"
+
+[target.'cfg(target_os = "macos")'.dependencies]
+core-graphics = "0.5.0"
+core-text = "2.0"
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/build.rs
@@ -0,0 +1,54 @@
+/* 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 std::env;
+use std::path::{Path, PathBuf};
+use std::io::prelude::*;
+use std::fs::{canonicalize, read_dir, File};
+
+fn write_shaders(glsl_files: Vec<PathBuf>, shader_file_path: &Path) {
+    let mut shader_file = File::create(shader_file_path).unwrap();
+
+    write!(shader_file, "/// AUTO GENERATED BY build.rs\n\n").unwrap();
+    write!(shader_file, "use std::collections::HashMap;\n").unwrap();
+    write!(shader_file, "lazy_static! {{\n").unwrap();
+    write!(shader_file, "  pub static ref SHADERS: HashMap<&'static str, &'static str> = {{\n").unwrap();
+    write!(shader_file, "    let mut h = HashMap::with_capacity({});\n", glsl_files.len()).unwrap();
+    for glsl in glsl_files {
+        let shader_name = glsl.file_name().unwrap().to_str().unwrap();
+        // strip .glsl
+        let shader_name = shader_name.replace(".glsl", "");
+        let full_path = canonicalize(&glsl).unwrap();
+        let full_name = full_path.as_os_str().to_str().unwrap();
+        // if someone is building on a network share, I'm sorry.
+        let full_name = full_name.replace("\\\\?\\", "");
+        let full_name = full_name.replace("\\", "/");
+        write!(shader_file, "    h.insert(\"{}\", include_str!(\"{}\"));\n",
+               shader_name, full_name).unwrap();
+    }
+    write!(shader_file, "    h\n").unwrap(); 
+    write!(shader_file, "  }};\n").unwrap(); 
+    write!(shader_file, "}}\n").unwrap(); 
+}
+
+fn main() {
+    let out_dir = env::var("OUT_DIR").unwrap_or("out".to_owned());
+
+    let shaders_file = Path::new(&out_dir).join("shaders.rs");
+    let mut glsl_files = vec![];
+
+    println!("cargo:rerun-if-changed=res");
+    let res_dir = Path::new("res");
+    for entry in read_dir(res_dir).unwrap() {
+        let entry = entry.unwrap();
+        let path = entry.path();
+
+        if entry.file_name().to_str().unwrap().ends_with(".glsl") {
+            println!("cargo:rerun-if-changed={}", path.display());
+            glsl_files.push(path.to_owned());
+        }
+    }
+
+    write_shaders(glsl_files, &shaders_file);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/clip_shared.glsl
@@ -0,0 +1,91 @@
+#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/. */
+
+#ifdef WR_VERTEX_SHADER
+
+#define SEGMENT_ALL         0
+#define SEGMENT_CORNER_TL   1
+#define SEGMENT_CORNER_TR   2
+#define SEGMENT_CORNER_BL   3
+#define SEGMENT_CORNER_BR   4
+
+in int aClipRenderTaskIndex;
+in int aClipLayerIndex;
+in int aClipDataIndex;
+in int aClipSegmentIndex;
+
+struct CacheClipInstance {
+    int render_task_index;
+    int layer_index;
+    int data_index;
+    int segment_index;
+};
+
+CacheClipInstance fetch_clip_item(int index) {
+    CacheClipInstance cci;
+
+    cci.render_task_index = aClipRenderTaskIndex;
+    cci.layer_index = aClipLayerIndex;
+    cci.data_index = aClipDataIndex;
+    cci.segment_index = aClipSegmentIndex;
+
+    return cci;
+}
+
+// The transformed vertex function that always covers the whole clip area,
+// which is the intersection of all clip instances of a given primitive
+TransformVertexInfo write_clip_tile_vertex(vec4 local_clip_rect,
+                                           Layer layer,
+                                           ClipArea area,
+                                           int segment_index) {
+    vec2 lp0_base = local_clip_rect.xy;
+    vec2 lp1_base = local_clip_rect.xy + local_clip_rect.zw;
+
+    vec2 lp0 = clamp_rect(lp0_base, layer.local_clip_rect);
+    vec2 lp1 = clamp_rect(lp1_base, layer.local_clip_rect);
+    vec4 clipped_local_rect = vec4(lp0, lp1 - lp0);
+
+    vec2 outer_p0 = area.screen_origin_target_index.xy;
+    vec2 outer_p1 = outer_p0 + area.task_bounds.zw - area.task_bounds.xy;
+    vec2 inner_p0 = area.inner_rect.xy;
+    vec2 inner_p1 = area.inner_rect.zw;
+
+    vec2 p0, p1;
+    switch (segment_index) {
+        case SEGMENT_ALL:
+            p0 = outer_p0;
+            p1 = outer_p1;
+            break;
+        case SEGMENT_CORNER_TL:
+            p0 = outer_p0;
+            p1 = inner_p0;
+            break;
+        case SEGMENT_CORNER_BL:
+            p0 = vec2(outer_p0.x, outer_p1.y);
+            p1 = vec2(inner_p0.x, inner_p1.y);
+            break;
+        case SEGMENT_CORNER_TR:
+            p0 = vec2(outer_p1.x, outer_p1.y);
+            p1 = vec2(inner_p1.x, inner_p1.y);
+            break;
+        case SEGMENT_CORNER_BR:
+            p0 = vec2(outer_p1.x, outer_p0.y);
+            p1 = vec2(inner_p1.x, inner_p0.y);
+            break;
+    }
+
+    vec2 actual_pos = mix(p0, p1, aPosition.xy);
+
+    vec4 layer_pos = get_layer_pos(actual_pos / uDevicePixelRatio, layer);
+
+    // compute the point position in side the layer, in CSS space
+    vec2 vertex_pos = actual_pos + area.task_bounds.xy - area.screen_origin_target_index.xy;
+
+    gl_Position = uTransform * vec4(vertex_pos, 0.0, 1);
+
+    return TransformVertexInfo(layer_pos.xyw, actual_pos, clipped_local_rect);
+}
+
+#endif //WR_VERTEX_SHADER
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_blur.fs.glsl
@@ -0,0 +1,40 @@
+#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/. */
+
+// TODO(gw): Write a fast path blur that handles smaller blur radii
+//           with a offset / weight uniform table and a constant
+//           loop iteration count!
+
+// TODO(gw): Make use of the bilinear sampling trick to reduce
+//           the number of texture fetches needed for a gaussian blur.
+
+float gauss(float x, float sigma) {
+    return (1.0 / sqrt(6.283185307179586 * sigma * sigma)) * exp(-(x * x) / (2.0 * sigma * sigma));
+}
+
+void main(void) {
+    vec4 cache_sample = texture(sCache, vUv);
+    vec4 color = vec4(cache_sample.rgb, 1.0) * (cache_sample.a * gauss(0.0, vSigma));
+
+    for (int i=1 ; i < vBlurRadius ; ++i) {
+        vec2 offset = vec2(float(i)) * vOffsetScale;
+
+        vec2 st0 = clamp(vUv.xy + offset, vUvRect.xy, vUvRect.zw);
+        vec4 color0 = texture(sCache, vec3(st0, vUv.z));
+
+        vec2 st1 = clamp(vUv.xy - offset, vUvRect.xy, vUvRect.zw);
+        vec4 color1 = texture(sCache, vec3(st1, vUv.z));
+
+        // Alpha must be premultiplied in order to properly blur the alpha channel.
+        float weight = gauss(float(i), vSigma);
+        color += vec4(color0.rgb * color0.a, color0.a) * weight;
+        color += vec4(color1.rgb * color1.a, color1.a) * weight;
+    }
+
+    // Unpremultiply the alpha.
+    color.rgb /= color.a;
+
+    oFragColor = color;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_blur.glsl
@@ -0,0 +1,10 @@
+#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/. */
+
+varying vec3 vUv;
+flat varying vec4 vUvRect;
+flat varying vec2 vOffsetScale;
+flat varying float vSigma;
+flat varying int vBlurRadius;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_blur.vs.glsl
@@ -0,0 +1,65 @@
+#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/. */
+
+// Applies a separable gaussian blur in one direction, as specified
+// by the dir field in the blur command.
+
+#define DIR_HORIZONTAL  0
+#define DIR_VERTICAL    1
+
+in int aBlurRenderTaskIndex;
+in int aBlurSourceTaskIndex;
+in int aBlurDirection;
+
+struct BlurCommand {
+    int task_id;
+    int src_task_id;
+    int dir;
+};
+
+BlurCommand fetch_blur() {
+    BlurCommand blur;
+
+    blur.task_id = aBlurRenderTaskIndex;
+    blur.src_task_id = aBlurSourceTaskIndex;
+    blur.dir = aBlurDirection;
+
+    return blur;
+}
+
+void main(void) {
+    BlurCommand cmd = fetch_blur();
+    RenderTaskData task = fetch_render_task(cmd.task_id);
+    RenderTaskData src_task = fetch_render_task(cmd.src_task_id);
+
+    vec4 local_rect = task.data0;
+
+    vec2 pos = mix(local_rect.xy,
+                   local_rect.xy + local_rect.zw,
+                   aPosition.xy);
+
+    vec2 texture_size = vec2(textureSize(sCache, 0).xy);
+    vUv.z = src_task.data1.x;
+    vBlurRadius = int(task.data1.y);
+    vSigma = task.data1.y * 0.5;
+
+    switch (cmd.dir) {
+        case DIR_HORIZONTAL:
+            vOffsetScale = vec2(1.0 / texture_size.x, 0.0);
+            break;
+        case DIR_VERTICAL:
+            vOffsetScale = vec2(0.0, 1.0 / texture_size.y);
+            break;
+    }
+
+    vUvRect = vec4(src_task.data0.xy, src_task.data0.xy + src_task.data0.zw);
+    vUvRect /= texture_size.xyxy;
+
+    vec2 uv0 = src_task.data0.xy / texture_size;
+    vec2 uv1 = (src_task.data0.xy + src_task.data0.zw) / texture_size;
+    vUv.xy = mix(uv0, uv1, aPosition.xy);
+
+    gl_Position = uTransform * vec4(pos, 0.0, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_box_shadow.fs.glsl
@@ -0,0 +1,148 @@
+#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/. */
+
+// See http://asciimath.org to render the equations here.
+
+// The Gaussian function used for blurring:
+//
+//     G_sigma(x) = 1/sqrt(2 pi sigma^2) e^(-x^2/(2 sigma^2))
+float gauss(float x, float sigma) {
+    float sigmaPow2 = sigma * sigma;
+    return 1.0 / sqrt(6.283185307179586 * sigmaPow2) * exp(-(x * x) / (2.0 * sigmaPow2));
+}
+
+// An approximation of the error function, which is related to the integral of the Gaussian
+// function:
+//
+//     "erf"(x) = 2/sqrt(pi) int_0^x e^(-t^2) dt
+//              ~~ 1 - 1 / (1 + a_1 x + a_2 x^2 + a_3 x^3 + a_4 x^4)^4
+//
+// where:
+//
+//     a_1 = 0.278393, a_2 = 0.230389, a_3 = 0.000972, a_4 = 0.078108
+//
+// This approximation is accurate to `5 xx 10^-4`, more than accurate enough for our purposes.
+//
+// See: https://en.wikipedia.org/wiki/Error_function#Approximation_with_elementary_functions
+float erf(float x) {
+    bool negative = x < 0.0;
+    if (negative)
+        x = -x;
+    float x2 = x * x;
+    float x3 = x2 * x;
+    float x4 = x2 * x2;
+    float denom = 1.0 + 0.278393 * x + 0.230389 * x2 + 0.000972 * x3 + 0.078108 * x4;
+    float result = 1.0 - 1.0 / (denom * denom * denom * denom);
+    return negative ? -result : result;
+}
+
+// A useful helper for calculating integrals of the Gaussian function via the error function:
+//
+//      "erf"_sigma(x) = 2 int 1/sqrt(2 pi sigma^2) e^(-x^2/(2 sigma^2)) dx
+//                     = "erf"(x/(sigma sqrt(2)))
+float erfSigma(float x, float sigma) {
+    return erf(x / (sigma * 1.4142135623730951));
+}
+
+// Returns the blurred color value from the box itself (not counting any rounded corners). `p_0` is
+// the vector distance to the top left corner of the box; `p_1` is the vector distance to its
+// bottom right corner.
+//
+//      "colorFromRect"_sigma(p_0, p_1)
+//          = int_{p_{0_y}}^{p_{1_y}} int_{p_{1_x}}^{p_{0_x}} G_sigma(y) G_sigma(x) dx dy
+//          = 1/4 ("erf"_sigma(p_{1_x}) - "erf"_sigma(p_{0_x}))
+//              ("erf"_sigma(p_{1_y}) - "erf"_sigma(p_{0_y}))
+float colorFromRect(vec2 p0, vec2 p1, float sigma) {
+    return (erfSigma(p1.x, sigma) - erfSigma(p0.x, sigma)) *
+        (erfSigma(p1.y, sigma) - erfSigma(p0.y, sigma)) / 4.0;
+}
+
+// Returns the `x` coordinate on the ellipse with the given radii for the given `y` coordinate:
+//
+//      "ellipsePoint"(y, y_0, a, b) = a sqrt(1 - ((y - y_0) / b)^2)
+float ellipsePoint(float y, float y0, vec2 radii) {
+    float bStep = (y - y0) / radii.y;
+    return radii.x * sqrt(1.0 - bStep * bStep);
+}
+
+// A helper function to compute the value that needs to be subtracted to accommodate the border
+// corners.
+//
+//     "colorCutout"_sigma(x_{0_l}, x_{0_r}, y_0, y_{min}, y_{max}, a, b)
+//          = int_{y_{min}}^{y_{max}}
+//              int_{x_{0_r} + "ellipsePoint"(y, y_0, a, b)}^{x_{0_r} + a} G_sigma(y) G_sigma(x) dx
+//              + int_{x_{0_l} - a}^{x_{0_l} - "ellipsePoint"(y, y_0, a, b)} G_sigma(y) G_sigma(x)
+//                  dx dy
+//          = int_{y_{min}}^{y_{max}} 1/2 G_sigma(y)
+//              ("erf"_sigma(x_{0_r} + a) - "erf"_sigma(x_{0_r} + "ellipsePoint"(y, y_0, a, b)) +
+//               "erf"_sigma(x_{0_l} - "ellipsePoint"(y, y_0, a, b)) - "erf"_sigma(x_{0_l} - a))
+//
+// with the outer integral evaluated numerically.
+float colorCutoutGeneral(float x0l,
+                         float x0r,
+                         float y0,
+                         float yMin,
+                         float yMax,
+                         vec2 radii,
+                         float sigma) {
+    float sum = 0.0;
+    for (float y = yMin; y <= yMax; y += 1.0) {
+        float xEllipsePoint = ellipsePoint(y, y0, radii);
+        sum += gauss(y, sigma) *
+            (erfSigma(x0r + radii.x, sigma) - erfSigma(x0r + xEllipsePoint, sigma) +
+             erfSigma(x0l - xEllipsePoint, sigma) - erfSigma(x0l - radii.x, sigma));
+    }
+    return sum / 2.0;
+}
+
+// The value that needs to be subtracted to accommodate the top border corners.
+float colorCutoutTop(float x0l, float x0r, float y0, vec2 radii, float sigma) {
+    return colorCutoutGeneral(x0l, x0r, y0, y0, y0 + radii.y, radii, sigma);
+}
+
+// The value that needs to be subtracted to accommodate the bottom border corners.
+float colorCutoutBottom(float x0l, float x0r, float y0, vec2 radii, float sigma) {
+    return colorCutoutGeneral(x0l, x0r, y0, y0 - radii.y, y0, radii, sigma);
+}
+
+// The blurred color value for the point at `pos` with the top left corner of the box at
+// `p_{0_"rect"}` and the bottom right corner of the box at `p_{1_"rect"}`.
+float color(vec2 pos, vec2 p0Rect, vec2 p1Rect, vec2 radii, float sigma) {
+    // Compute the vector distances `p_0` and `p_1`.
+    vec2 p0 = p0Rect - pos, p1 = p1Rect - pos;
+
+    // Compute the basic color `"colorFromRect"_sigma(p_0, p_1)`. This is all we have to do if
+    // the box is unrounded.
+    float cRect = colorFromRect(p0, p1, sigma);
+    if (radii.x == 0.0 || radii.y == 0.0)
+        return cRect;
+
+    // Compute the inner corners of the box, taking border radii into account: `x_{0_l}`,
+    // `y_{0_t}`, `x_{0_r}`, and `y_{0_b}`.
+    float x0l = p0.x + radii.x;
+    float y0t = p1.y - radii.y;
+    float x0r = p1.x - radii.x;
+    float y0b = p0.y + radii.y;
+
+    // Compute the final color:
+    //
+    //     "colorFromRect"_sigma(p_0, p_1) -
+    //          ("colorCutoutTop"_sigma(x_{0_l}, x_{0_r}, y_{0_t}, a, b) +
+    //           "colorCutoutBottom"_sigma(x_{0_l}, x_{0_r}, y_{0_b}, a, b))
+    float cCutoutTop = colorCutoutTop(x0l, x0r, y0t, radii, sigma);
+    float cCutoutBottom = colorCutoutBottom(x0l, x0r, y0b, radii, sigma);
+    return cRect - (cCutoutTop + cCutoutBottom);
+}
+
+void main(void) {
+    vec2 pos = vPos.xy;
+    vec2 p0Rect = vBoxShadowRect.xy, p1Rect = vBoxShadowRect.zw;
+    vec2 radii = vBorderRadii.xy;
+    float sigma = vBlurRadius / 2.0;
+    float value = color(pos, p0Rect, p1Rect, radii, sigma);
+
+    value = max(value, 0.0);
+    oFragColor = vec4(1.0, 1.0, 1.0, vInverted == 1.0 ? 1.0 - value : value);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_box_shadow.glsl
@@ -0,0 +1,10 @@
+#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/. */
+
+varying vec2 vPos;
+flat varying vec2 vBorderRadii;
+flat varying float vBlurRadius;
+flat varying vec4 vBoxShadowRect;
+flat varying float vInverted;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_box_shadow.vs.glsl
@@ -0,0 +1,31 @@
+#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) {
+    CachePrimitiveInstance cpi = fetch_cache_instance();
+    RenderTaskData task = fetch_render_task(cpi.render_task_index);
+    BoxShadow bs = fetch_boxshadow(cpi.specific_prim_index);
+
+    vec2 p0 = task.data0.xy;
+    vec2 p1 = p0 + task.data0.zw;
+
+    vec2 pos = mix(p0, p1, aPosition.xy);
+
+    vBorderRadii = bs.border_radius_edge_size_blur_radius_inverted.xx;
+    vBlurRadius = bs.border_radius_edge_size_blur_radius_inverted.z;
+    vInverted = bs.border_radius_edge_size_blur_radius_inverted.w;
+    vBoxShadowRect = vec4(bs.bs_rect.xy, bs.bs_rect.xy + bs.bs_rect.zw);
+
+    // The fragment shader expects logical units, beginning at where the
+    // blur radius begins.
+    // The first path of the equation gets the virtual position in
+    // logical pixels within the patch rectangle (accounting for
+    // bilinear offset). Then we add the start position of the
+    // box shadow rect and subtract the blur radius to get the
+    // virtual coordinates that the FS expects.
+    vPos = (pos - 1.0 - p0) / uDevicePixelRatio + bs.bs_rect.xy - vec2(2.0 * vBlurRadius);
+
+    gl_Position = uTransform * vec4(pos, 0.0, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_clip_image.fs.glsl
@@ -0,0 +1,16 @@
+/* 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) {
+    float alpha = 1.f;
+    vec2 local_pos = init_transform_fs(vPos, vLocalRect, alpha);
+
+    bool repeat_mask = false; //TODO
+    vec2 clamped_mask_uv = repeat_mask ? fract(vClipMaskUv.xy) :
+        clamp(vClipMaskUv.xy, vec2(0.0, 0.0), vec2(1.0, 1.0));
+    vec2 source_uv = clamped_mask_uv * vClipMaskUvRect.zw + vClipMaskUvRect.xy;
+    float clip_alpha = texture(sMask, source_uv).r; //careful: texture has type A8
+
+    oFragColor = vec4(min(alpha, clip_alpha), 1.0, 1.0, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_clip_image.glsl
@@ -0,0 +1,9 @@
+#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/. */
+
+varying vec3 vPos;
+flat varying vec4 vLocalRect;
+flat varying vec4 vClipMaskUvRect;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_clip_image.vs.glsl
@@ -0,0 +1,39 @@
+#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/. */
+
+struct ImageMaskData {
+    vec4 uv_rect;
+    vec4 local_rect;
+};
+
+ImageMaskData fetch_mask_data(int index) {
+    ImageMaskData info;
+
+    ivec2 uv = get_fetch_uv_2(index);
+
+    info.uv_rect = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
+    info.local_rect = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
+
+    return info;
+}
+
+void main(void) {
+    CacheClipInstance cci = fetch_clip_item(gl_InstanceID);
+    ClipArea area = fetch_clip_area(cci.render_task_index);
+    Layer layer = fetch_layer(cci.layer_index);
+    ImageMaskData mask = fetch_mask_data(cci.data_index);
+    vec4 local_rect = mask.local_rect;
+
+    TransformVertexInfo vi = write_clip_tile_vertex(local_rect,
+                                                    layer,
+                                                    area,
+                                                    cci.segment_index);
+    vLocalRect = vi.clipped_local_rect;
+    vPos = vi.local_pos;
+
+    vClipMaskUv = vec3((vPos.xy / vPos.z - local_rect.xy) / local_rect.zw, 0.0);
+    vec2 texture_size = vec2(textureSize(sMask, 0));
+    vClipMaskUvRect = mask.uv_rect / texture_size.xyxy;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_clip_rectangle.fs.glsl
@@ -0,0 +1,44 @@
+/* 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/. */
+
+float rounded_rect(vec2 pos) {
+    vec2 ref_tl = vClipRect.xy + vec2( vClipRadius.x,  vClipRadius.x);
+    vec2 ref_tr = vClipRect.zy + vec2(-vClipRadius.y,  vClipRadius.y);
+    vec2 ref_br = vClipRect.zw + vec2(-vClipRadius.z, -vClipRadius.z);
+    vec2 ref_bl = vClipRect.xw + vec2( vClipRadius.w, -vClipRadius.w);
+
+    float d_tl = distance(pos, ref_tl);
+    float d_tr = distance(pos, ref_tr);
+    float d_br = distance(pos, ref_br);
+    float d_bl = distance(pos, ref_bl);
+
+    float pixels_per_fragment = length(fwidth(pos.xy));
+    float nudge = 0.5 * pixels_per_fragment;
+    vec4 distances = vec4(d_tl, d_tr, d_br, d_bl) - vClipRadius + nudge;
+
+    bvec4 is_out = bvec4(pos.x < ref_tl.x && pos.y < ref_tl.y,
+                         pos.x > ref_tr.x && pos.y < ref_tr.y,
+                         pos.x > ref_br.x && pos.y > ref_br.y,
+                         pos.x < ref_bl.x && pos.y > ref_bl.y);
+
+    float distance_from_border = dot(vec4(is_out),
+                                     max(vec4(0.0, 0.0, 0.0, 0.0), distances));
+
+    // Move the distance back into pixels.
+    distance_from_border /= pixels_per_fragment;
+    // Apply a more gradual fade out to transparent.
+    //distance_from_border -= 0.5;
+
+    return 1.0 - smoothstep(0.0, 1.0, distance_from_border);
+}
+
+
+void main(void) {
+    float alpha = 1.f;
+    vec2 local_pos = init_transform_fs(vPos, vLocalRect, alpha);
+
+    float clip_alpha = rounded_rect(local_pos);
+
+    oFragColor = vec4(min(alpha, clip_alpha), 0.0, 0.0, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_clip_rectangle.glsl
@@ -0,0 +1,10 @@
+#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/. */
+
+varying vec3 vPos;
+flat varying vec4 vLocalRect;
+flat varying vec4 vClipRect;
+flat varying vec4 vClipRadius;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_clip_rectangle.vs.glsl
@@ -0,0 +1,78 @@
+#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/. */
+
+struct ClipRect {
+    vec4 rect;
+    vec4 dummy;
+};
+
+ClipRect fetch_clip_rect(int index) {
+    ClipRect rect;
+
+    ivec2 uv = get_fetch_uv_2(index);
+
+    rect.rect = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
+    //rect.dummy = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
+    rect.dummy = vec4(0.0, 0.0, 0.0, 0.0);
+
+    return rect;
+}
+
+struct ClipCorner {
+    vec4 rect;
+    vec4 outer_inner_radius;
+};
+
+ClipCorner fetch_clip_corner(int index) {
+    ClipCorner corner;
+
+    ivec2 uv = get_fetch_uv_2(index);
+
+    corner.rect = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
+    corner.outer_inner_radius = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
+
+    return corner;
+}
+
+struct ClipData {
+    ClipRect rect;
+    ClipCorner top_left;
+    ClipCorner top_right;
+    ClipCorner bottom_left;
+    ClipCorner bottom_right;
+};
+
+ClipData fetch_clip(int index) {
+    ClipData clip;
+
+    clip.rect = fetch_clip_rect(index + 0);
+    clip.top_left = fetch_clip_corner(index + 1);
+    clip.top_right = fetch_clip_corner(index + 2);
+    clip.bottom_left = fetch_clip_corner(index + 3);
+    clip.bottom_right = fetch_clip_corner(index + 4);
+
+    return clip;
+}
+
+void main(void) {
+    CacheClipInstance cci = fetch_clip_item(gl_InstanceID);
+    ClipArea area = fetch_clip_area(cci.render_task_index);
+    Layer layer = fetch_layer(cci.layer_index);
+    ClipData clip = fetch_clip(cci.data_index);
+    vec4 local_rect = clip.rect.rect;
+
+    TransformVertexInfo vi = write_clip_tile_vertex(local_rect,
+                                                    layer,
+                                                    area,
+                                                    cci.segment_index);
+    vLocalRect = vi.clipped_local_rect;
+    vPos = vi.local_pos;
+
+    vClipRect = vec4(local_rect.xy, local_rect.xy + local_rect.zw);
+    vClipRadius = vec4(clip.top_left.outer_inner_radius.x,
+                       clip.top_right.outer_inner_radius.x,
+                       clip.bottom_right.outer_inner_radius.x,
+                       clip.bottom_left.outer_inner_radius.x);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_text_run.fs.glsl
@@ -0,0 +1,9 @@
+#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) {
+    float a = texture(sColor0, vUv).a;
+    oFragColor = vec4(vColor.rgb, vColor.a * a);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_text_run.glsl
@@ -0,0 +1,7 @@
+#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/. */
+
+varying vec2 vUv;
+flat varying vec4 vColor;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_text_run.vs.glsl
@@ -0,0 +1,36 @@
+#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/. */
+
+// Draw a text run to a cache target. These are always
+// drawn un-transformed. These are used for effects such
+// as text-shadow.
+
+void main(void) {
+    CachePrimitiveInstance cpi = fetch_cache_instance();
+    RenderTaskData task = fetch_render_task(cpi.render_task_index);
+    TextRun text = fetch_text_run(cpi.specific_prim_index);
+    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);
+    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,
+                   aPosition.xy);
+	vUv = mix(st0, st1, aPosition.xy);
+	vColor = text.color;
+
+    gl_Position = uTransform * vec4(pos, 0.0, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/debug_color.fs.glsl
@@ -0,0 +1,10 @@
+/* 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/. */
+
+varying vec4 vColor;
+
+void main(void)
+{
+    oFragColor = vColor;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/debug_color.vs.glsl
@@ -0,0 +1,14 @@
+/* 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/. */
+
+in vec4 aColor;
+varying vec4 vColor;
+
+void main(void)
+{
+    vColor = aColor;
+    vec4 pos = vec4(aPosition, 1.0);
+    pos.xy = floor(pos.xy * uDevicePixelRatio + 0.5) / uDevicePixelRatio;
+    gl_Position = uTransform * pos;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/debug_font.fs.glsl
@@ -0,0 +1,16 @@
+/* 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/. */
+
+varying vec2 vColorTexCoord;
+varying vec4 vColor;
+
+void main(void)
+{
+#ifdef SERVO_ES2
+    float alpha = texture(sColor0, vColorTexCoord.xy).a;
+#else
+    float alpha = texture(sColor0, vColorTexCoord.xy).r;
+#endif
+    oFragColor = vec4(vColor.xyz, vColor.w * alpha);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/debug_font.vs.glsl
@@ -0,0 +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/. */
+
+in vec4 aColor;
+in vec4 aColorTexCoord;
+
+varying vec2 vColorTexCoord;
+varying vec4 vColor;
+
+void main(void)
+{
+    vColor = aColor;
+    vColorTexCoord = aColorTexCoord.xy;
+    vec4 pos = vec4(aPosition, 1.0);
+    pos.xy = floor(pos.xy * uDevicePixelRatio + 0.5) / uDevicePixelRatio;
+    gl_Position = uTransform * pos;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/prim_shared.glsl
@@ -0,0 +1,665 @@
+#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/. */
+
+#if defined(GL_ES)
+    #if GL_ES == 1
+        #ifdef GL_FRAGMENT_PRECISION_HIGH
+        precision highp sampler2DArray;
+        #else
+        precision mediump sampler2DArray;
+        #endif
+    #endif
+#endif
+
+#define PST_TOP_LEFT     0
+#define PST_TOP          1
+#define PST_TOP_RIGHT    2
+#define PST_RIGHT        3
+#define PST_BOTTOM_RIGHT 4
+#define PST_BOTTOM       5
+#define PST_BOTTOM_LEFT  6
+#define PST_LEFT         7
+
+#define BORDER_LEFT      0
+#define BORDER_TOP       1
+#define BORDER_RIGHT     2
+#define BORDER_BOTTOM    3
+
+#define UV_NORMALIZED    uint(0)
+#define UV_PIXEL         uint(1)
+
+#define MAX_STOPS_PER_ANGLE_GRADIENT 8
+#define MAX_STOPS_PER_RADIAL_GRADIENT 8
+
+uniform sampler2DArray sCache;
+
+flat varying vec4 vClipMaskUvBounds;
+varying vec3 vClipMaskUv;
+
+#ifdef WR_VERTEX_SHADER
+
+#define VECS_PER_LAYER             13
+#define VECS_PER_RENDER_TASK        3
+#define VECS_PER_PRIM_GEOM          2
+
+#define GRADIENT_HORIZONTAL     0
+#define GRADIENT_VERTICAL       1
+#define GRADIENT_ROTATED        2
+
+uniform sampler2D sLayers;
+uniform sampler2D sRenderTasks;
+uniform sampler2D sPrimGeometry;
+
+uniform sampler2D sData16;
+uniform sampler2D sData32;
+uniform sampler2D sData64;
+uniform sampler2D sData128;
+uniform sampler2D sResourceRects;
+
+// Instanced attributes
+in int aGlobalPrimId;
+in int aPrimitiveAddress;
+in int aTaskIndex;
+in int aClipTaskIndex;
+in int aLayerIndex;
+in int aElementIndex;
+in ivec2 aUserData;
+in int aZIndex;
+
+// get_fetch_uv is a macro to work around a macOS Intel driver parsing bug.
+// TODO: convert back to a function once the driver issues are resolved, if ever.
+// https://github.com/servo/webrender/pull/623
+// https://github.com/servo/servo/issues/13953
+#define get_fetch_uv(i, vpi)  ivec2(vpi * (i % (WR_MAX_VERTEX_TEXTURE_WIDTH/vpi)), i / (WR_MAX_VERTEX_TEXTURE_WIDTH/vpi))
+
+ivec2 get_fetch_uv_1(int index) {
+    return get_fetch_uv(index, 1);
+}
+
+ivec2 get_fetch_uv_2(int index) {
+    return get_fetch_uv(index, 2);
+}
+
+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 Layer {
+    mat4 transform;
+    mat4 inv_transform;
+    vec4 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
+    // of more than 8 texels doesn't work on some versions
+    // of OSX.
+    ivec2 uv = get_fetch_uv(index, VECS_PER_LAYER);
+    ivec2 uv0 = ivec2(uv.x + 0, uv.y);
+    ivec2 uv1 = ivec2(uv.x + 8, uv.y);
+
+    layer.transform[0] = texelFetchOffset(sLayers, uv0, 0, ivec2(0, 0));
+    layer.transform[1] = texelFetchOffset(sLayers, uv0, 0, ivec2(1, 0));
+    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));
+
+    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;
+}
+
+struct RenderTaskData {
+    vec4 data0;
+    vec4 data1;
+    vec4 data2;
+};
+
+RenderTaskData fetch_render_task(int index) {
+    RenderTaskData task;
+
+    ivec2 uv = get_fetch_uv(index, VECS_PER_RENDER_TASK);
+
+    task.data0 = texelFetchOffset(sRenderTasks, uv, 0, ivec2(0, 0));
+    task.data1 = texelFetchOffset(sRenderTasks, uv, 0, ivec2(1, 0));
+    task.data2 = texelFetchOffset(sRenderTasks, uv, 0, ivec2(2, 0));
+
+    return task;
+}
+
+struct Tile {
+    vec4 screen_origin_task_origin;
+    vec4 size_target_index;
+};
+
+Tile fetch_tile(int index) {
+    RenderTaskData task = fetch_render_task(index);
+
+    Tile tile;
+    tile.screen_origin_task_origin = task.data0;
+    tile.size_target_index = task.data1;
+
+    return tile;
+}
+
+struct ClipArea {
+    vec4 task_bounds;
+    vec4 screen_origin_target_index;
+    vec4 inner_rect;
+};
+
+ClipArea fetch_clip_area(int index) {
+    ClipArea area;
+
+    if (index == 0x7FFFFFFF) { //special sentinel task index
+        area.task_bounds = vec4(0.0, 0.0, 0.0, 0.0);
+        area.screen_origin_target_index = vec4(0.0, 0.0, 0.0, 0.0);
+        area.inner_rect = vec4(0.0);
+    } else {
+        RenderTaskData task = fetch_render_task(index);
+        area.task_bounds = task.data0;
+        area.screen_origin_target_index = task.data1;
+        area.inner_rect = task.data2;
+    }
+
+    return area;
+}
+
+struct Gradient {
+    vec4 start_end_point;
+    vec4 kind;
+};
+
+Gradient fetch_gradient(int index) {
+    Gradient gradient;
+
+    ivec2 uv = get_fetch_uv_2(index);
+
+    gradient.start_end_point = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
+    gradient.kind = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
+
+    return gradient;
+}
+
+struct GradientStop {
+    vec4 color;
+    vec4 offset;
+};
+
+GradientStop fetch_gradient_stop(int index) {
+    GradientStop stop;
+
+    ivec2 uv = get_fetch_uv_2(index);
+
+    stop.color = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
+    stop.offset = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
+
+    return stop;
+}
+
+struct RadialGradient {
+    vec4 start_end_center;
+    vec4 start_end_radius;
+};
+
+RadialGradient fetch_radial_gradient(int index) {
+    RadialGradient gradient;
+
+    ivec2 uv = get_fetch_uv_2(index);
+
+    gradient.start_end_center = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
+    gradient.start_end_radius = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
+
+    return gradient;
+}
+
+struct Glyph {
+    vec4 offset;
+};
+
+Glyph fetch_glyph(int index) {
+    Glyph glyph;
+
+    ivec2 uv = get_fetch_uv_1(index);
+
+    glyph.offset = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
+
+    return glyph;
+}
+
+vec4 fetch_instance_geometry(int index) {
+    ivec2 uv = get_fetch_uv_1(index);
+
+    vec4 rect = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
+
+    return rect;
+}
+
+struct PrimitiveGeometry {
+    vec4 local_rect;
+    vec4 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));
+
+    return pg;
+}
+
+struct PrimitiveInstance {
+    int global_prim_index;
+    int specific_prim_index;
+    int render_task_index;
+    int clip_task_index;
+    int layer_index;
+    int sub_index;
+    int z;
+    ivec2 user_data;
+};
+
+PrimitiveInstance fetch_prim_instance() {
+    PrimitiveInstance pi;
+
+    pi.global_prim_index = aGlobalPrimId;
+    pi.specific_prim_index = aPrimitiveAddress;
+    pi.render_task_index = aTaskIndex;
+    pi.clip_task_index = aClipTaskIndex;
+    pi.layer_index = aLayerIndex;
+    pi.sub_index = aElementIndex;
+    pi.user_data = aUserData;
+    pi.z = aZIndex;
+
+    return pi;
+}
+
+struct CachePrimitiveInstance {
+    int global_prim_index;
+    int specific_prim_index;
+    int render_task_index;
+    int sub_index;
+    ivec2 user_data;
+};
+
+CachePrimitiveInstance fetch_cache_instance() {
+    CachePrimitiveInstance cpi;
+
+    PrimitiveInstance pi = fetch_prim_instance();
+
+    cpi.global_prim_index = pi.global_prim_index;
+    cpi.specific_prim_index = pi.specific_prim_index;
+    cpi.render_task_index = pi.render_task_index;
+    cpi.sub_index = pi.sub_index;
+    cpi.user_data = pi.user_data;
+
+    return cpi;
+}
+
+struct Primitive {
+    Layer layer;
+    Tile tile;
+    ClipArea clip_area;
+    vec4 local_rect;
+    vec4 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;
+};
+
+Primitive load_primitive_custom(PrimitiveInstance pi) {
+    Primitive prim;
+
+    prim.layer = fetch_layer(pi.layer_index);
+    prim.tile = fetch_tile(pi.render_task_index);
+    prim.clip_area = fetch_clip_area(pi.clip_task_index);
+
+    PrimitiveGeometry pg = fetch_prim_geometry(pi.global_prim_index);
+    prim.local_rect = pg.local_rect;
+    prim.local_clip_rect = pg.local_clip_rect;
+
+    prim.prim_index = pi.specific_prim_index;
+    prim.sub_index = pi.sub_index;
+    prim.user_data = pi.user_data;
+    prim.z = float(pi.z);
+
+    return prim;
+}
+
+Primitive load_primitive() {
+    PrimitiveInstance pi = fetch_prim_instance();
+
+    return load_primitive_custom(pi);
+}
+
+
+// Return the intersection of the plane (set up by "normal" and "point")
+// with the ray (set up by "ray_origin" and "ray_dir"),
+// writing the resulting scaler into "t".
+bool ray_plane(vec3 normal, vec3 point, vec3 ray_origin, vec3 ray_dir, out float t)
+{
+    float denom = dot(normal, ray_dir);
+    if (denom > 1e-6) {
+        vec3 d = point - ray_origin;
+        t = dot(d, normal) / denom;
+        return t >= 0.0;
+    }
+
+    return false;
+}
+
+// Apply the inverse transform "inv_transform"
+// to the reference point "ref" in CSS space,
+// producing a local point on a layer plane,
+// set by a base point "a" and a normal "n".
+vec4 untransform(vec2 ref, vec3 n, vec3 a, mat4 inv_transform) {
+    vec3 p = vec3(ref, -10000.0);
+    vec3 d = vec3(0, 0, 1.0);
+
+    float t = 0.0;
+    // get an intersection of the layer plane with Z axis vector,
+    // originated from the "ref" point
+    ray_plane(n, a, p, d, t);
+    float z = p.z + d.z * t; // Z of the visible point on the layer
+
+    vec4 r = inv_transform * vec4(ref, z, 1.0);
+    return r;
+}
+
+// Given a CSS space position, transform it back into the layer space.
+vec4 get_layer_pos(vec2 pos, Layer layer) {
+    // get 3 of the layer corners in CSS space
+    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;
+    vec2 local_clamped_pos;
+    vec2 global_clamped_pos;
+};
+
+VertexInfo write_vertex(vec4 instance_rect,
+                        vec4 local_clip_rect,
+                        float z,
+                        Layer layer,
+                        Tile tile) {
+    vec2 p0 = floor(0.5 + instance_rect.xy * uDevicePixelRatio) / uDevicePixelRatio;
+    vec2 p1 = floor(0.5 + (instance_rect.xy + instance_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio;
+
+    vec2 local_pos = mix(p0, p1, aPosition.xy);
+
+    vec2 cp0 = floor(0.5 + local_clip_rect.xy * uDevicePixelRatio) / uDevicePixelRatio;
+    vec2 cp1 = floor(0.5 + (local_clip_rect.xy + local_clip_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio;
+    local_pos = clamp(local_pos, cp0, cp1);
+
+    local_pos = clamp_rect(local_pos, layer.local_clip_rect);
+
+    vec4 world_pos = layer.transform * vec4(local_pos, 0.0, 1.0);
+    world_pos.xyz /= world_pos.w;
+
+    vec2 device_pos = world_pos.xy * uDevicePixelRatio;
+
+    vec2 clamped_pos = clamp(device_pos,
+                             tile.screen_origin_task_origin.xy,
+                             tile.screen_origin_task_origin.xy + tile.size_target_index.xy);
+
+    vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, world_pos.z, 1);
+    local_clamped_pos.xyz /= local_clamped_pos.w;
+
+    vec2 final_pos = clamped_pos + tile.screen_origin_task_origin.zw - tile.screen_origin_task_origin.xy;
+
+    gl_Position = uTransform * vec4(final_pos, z, 1.0);
+
+    VertexInfo vi = VertexInfo(Rect(p0, p1), local_clamped_pos.xy, clamped_pos.xy);
+    return vi;
+}
+
+#ifdef WR_FEATURE_TRANSFORM
+
+struct TransformVertexInfo {
+    vec3 local_pos;
+    vec2 global_clamped_pos;
+    vec4 clipped_local_rect;
+};
+
+TransformVertexInfo write_transform_vertex(vec4 instance_rect,
+                                           vec4 local_clip_rect,
+                                           float z,
+                                           Layer layer,
+                                           Tile tile) {
+    vec2 lp0_base = instance_rect.xy;
+    vec2 lp1_base = instance_rect.xy + instance_rect.zw;
+
+    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);
+
+    vec2 p0 = lp0;
+    vec2 p1 = vec2(lp1.x, lp0.y);
+    vec2 p2 = vec2(lp0.x, lp1.y);
+    vec2 p3 = lp1;
+
+    vec4 t0 = layer.transform * vec4(p0, 0, 1);
+    vec4 t1 = layer.transform * vec4(p1, 0, 1);
+    vec4 t2 = layer.transform * vec4(p2, 0, 1);
+    vec4 t3 = layer.transform * vec4(p3, 0, 1);
+
+    vec2 tp0 = t0.xy / t0.w;
+    vec2 tp1 = t1.xy / t1.w;
+    vec2 tp2 = t2.xy / t2.w;
+    vec2 tp3 = t3.xy / t3.w;
+
+    // compute a CSS space aligned bounding box
+    vec2 min_pos = min(min(tp0.xy, tp1.xy), min(tp2.xy, tp3.xy));
+    vec2 max_pos = max(max(tp0.xy, tp1.xy), max(tp2.xy, tp3.xy));
+
+    // clamp to the tile boundaries, in device space
+    vec2 min_pos_clamped = clamp(min_pos * uDevicePixelRatio,
+                                 tile.screen_origin_task_origin.xy,
+                                 tile.screen_origin_task_origin.xy + tile.size_target_index.xy);
+
+    vec2 max_pos_clamped = clamp(max_pos * uDevicePixelRatio,
+                                 tile.screen_origin_task_origin.xy,
+                                 tile.screen_origin_task_origin.xy + tile.size_target_index.xy);
+
+    // compute the device space position of this vertex
+    vec2 clamped_pos = mix(min_pos_clamped,
+                           max_pos_clamped,
+                           aPosition.xy);
+
+    // compute the point position in side the layer, in CSS space
+    vec4 layer_pos = get_layer_pos(clamped_pos / uDevicePixelRatio, layer);
+
+    // apply the task offset
+    vec2 final_pos = clamped_pos + tile.screen_origin_task_origin.zw - tile.screen_origin_task_origin.xy;
+
+    gl_Position = uTransform * vec4(final_pos, z, 1.0);
+
+    return TransformVertexInfo(layer_pos.xyw, clamped_pos, clipped_local_rect);
+}
+
+#endif //WR_FEATURE_TRANSFORM
+
+struct ResourceRect {
+    vec4 uv_rect;
+};
+
+ResourceRect fetch_resource_rect(int index) {
+    ResourceRect rect;
+
+    ivec2 uv = get_fetch_uv_1(index);
+
+    rect.uv_rect = texelFetchOffset(sResourceRects, uv, 0, ivec2(0, 0));
+
+    return rect;
+}
+
+struct Rectangle {
+    vec4 color;
+};
+
+Rectangle fetch_rectangle(int index) {
+    Rectangle rect;
+
+    ivec2 uv = get_fetch_uv_1(index);
+
+    rect.color = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
+
+    return rect;
+}
+
+struct TextRun {
+    vec4 color;
+};
+
+TextRun fetch_text_run(int index) {
+    TextRun text;
+
+    ivec2 uv = get_fetch_uv_1(index);
+
+    text.color = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
+
+    return text;
+}
+
+struct Image {
+    vec4 stretch_size_and_tile_spacing;  // Size of the actual image and amount of space between
+                                         //     tiled instances of this image.
+};
+
+Image fetch_image(int index) {
+    Image image;
+
+    ivec2 uv = get_fetch_uv_1(index);
+
+    image.stretch_size_and_tile_spacing = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
+
+    return image;
+}
+
+// YUV color spaces
+#define YUV_REC601 1
+#define YUV_REC709 2
+
+struct YuvImage {
+    vec4 y_st_rect;
+    vec4 u_st_rect;
+    vec4 v_st_rect;
+    vec2 size;
+    int color_space;
+};
+
+YuvImage fetch_yuv_image(int index) {
+    YuvImage image;
+
+    ivec2 uv = get_fetch_uv_4(index);
+
+    image.y_st_rect = texelFetchOffset(sData64, uv, 0, ivec2(0, 0));
+    image.u_st_rect = texelFetchOffset(sData64, uv, 0, ivec2(1, 0));
+    image.v_st_rect = texelFetchOffset(sData64, uv, 0, ivec2(2, 0));
+    vec4 size_color_space = texelFetchOffset(sData64, uv, 0, ivec2(3, 0));
+    image.size = size_color_space.xy;
+    image.color_space = int(size_color_space.z);
+
+    return image;
+}
+
+struct BoxShadow {
+    vec4 src_rect;
+    vec4 bs_rect;
+    vec4 color;
+    vec4 border_radius_edge_size_blur_radius_inverted;
+};
+
+BoxShadow fetch_boxshadow(int index) {
+    BoxShadow bs;
+
+    ivec2 uv = get_fetch_uv_4(index);
+
+    bs.src_rect = texelFetchOffset(sData64, uv, 0, ivec2(0, 0));
+    bs.bs_rect = texelFetchOffset(sData64, uv, 0, ivec2(1, 0));
+    bs.color = texelFetchOffset(sData64, uv, 0, ivec2(2, 0));
+    bs.border_radius_edge_size_blur_radius_inverted = texelFetchOffset(sData64, uv, 0, ivec2(3, 0));
+
+    return bs;
+}
+
+void write_clip(vec2 global_pos, ClipArea area) {
+    vec2 texture_size = vec2(textureSize(sCache, 0).xy);
+    vec2 uv = global_pos + area.task_bounds.xy - area.screen_origin_target_index.xy;
+    vClipMaskUvBounds = area.task_bounds / texture_size.xyxy;
+    vClipMaskUv = vec3(uv / texture_size, area.screen_origin_target_index.z);
+}
+#endif //WR_VERTEX_SHADER
+
+#ifdef WR_FRAGMENT_SHADER
+float distance_from_rect(vec2 p, vec2 origin, vec2 size) {
+    vec2 clamped = clamp(p, origin, origin + size);
+    return distance(clamped, p);
+}
+
+vec2 init_transform_fs(vec3 local_pos, vec4 local_rect, out float fragment_alpha) {
+    fragment_alpha = 1.0;
+    vec2 pos = local_pos.xy / local_pos.z;
+
+    float border_distance = distance_from_rect(pos, local_rect.xy, local_rect.zw);
+    if (border_distance != 0.0) {
+        float delta = length(fwidth(local_pos.xy));
+        fragment_alpha = 1.0 - smoothstep(0.0, 1.0, border_distance / delta * 2.0);
+    }
+
+    return pos;
+}
+
+float do_clip() {
+    // anything outside of the mask is considered transparent
+    bvec4 inside = lessThanEqual(
+        vec4(vClipMaskUvBounds.xy, vClipMaskUv.xy),
+        vec4(vClipMaskUv.xy, vClipMaskUvBounds.zw));
+    // check for the dummy bounds, which are given to the opaque objects
+    return vClipMaskUvBounds.xy == vClipMaskUvBounds.zw ? 1.0:
+        all(inside) ? textureLod(sCache, vClipMaskUv, 0.0).r : 0.0;
+}
+#endif //WR_FRAGMENT_SHADER
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_angle_gradient.fs.glsl
@@ -0,0 +1,39 @@
+/* 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/. */
+
+float offset(int index) {
+    return vOffsets[index / 4][index % 4];
+}
+
+float linearStep(float lo, float hi, float x) {
+    float d = hi - lo;
+    float v = x - lo;
+    if (d != 0.0) {
+        v /= d;
+    }
+    return clamp(v, 0.0, 1.0);
+}
+
+void main(void) {
+    float angle = atan(-vEndPoint.y + vStartPoint.y,
+                        vEndPoint.x - vStartPoint.x);
+    float sa = sin(angle);
+    float ca = cos(angle);
+
+    float sx = vStartPoint.x * ca - vStartPoint.y * sa;
+    float ex = vEndPoint.x * ca - vEndPoint.y * sa;
+    float d = ex - sx;
+
+    float x = vPos.x * ca - vPos.y * sa;
+
+    oFragColor = mix(vColors[0],
+                     vColors[1],
+                     linearStep(sx + d * offset(0), sx + d * offset(1), x));
+
+    for (int i=1 ; i < vStopCount-1 ; ++i) {
+        oFragColor = mix(oFragColor,
+                         vColors[i+1],
+                         linearStep(sx + d * offset(i), sx + d * offset(i+1), x));
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_angle_gradient.glsl
@@ -0,0 +1,11 @@
+/* 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/. */
+
+flat varying int vStopCount;
+flat varying float vAngle;
+flat varying vec2 vStartPoint;
+flat varying vec2 vEndPoint;
+varying vec2 vPos;
+flat varying vec4 vColors[MAX_STOPS_PER_ANGLE_GRADIENT];
+flat varying vec4 vOffsets[MAX_STOPS_PER_ANGLE_GRADIENT/4];
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_angle_gradient.vs.glsl
@@ -0,0 +1,33 @@
+#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();
+    Gradient gradient = fetch_gradient(prim.prim_index);
+
+    VertexInfo vi = write_vertex(prim.local_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+
+    vStopCount = int(prim.user_data.x);
+    vPos = vi.local_clamped_pos;
+
+    // Snap the start/end points to device pixel units.
+    // I'm not sure this is entirely correct, but the
+    // old render path does this, and it is needed to
+    // make the angle gradient ref tests pass. It might
+    // be better to fix this higher up in DL construction
+    // and not snap here?
+    vStartPoint = floor(0.5 + gradient.start_end_point.xy * uDevicePixelRatio) / uDevicePixelRatio;
+    vEndPoint = floor(0.5 + gradient.start_end_point.zw * uDevicePixelRatio) / uDevicePixelRatio;
+
+    for (int i=0 ; i < vStopCount ; ++i) {
+        GradientStop stop = fetch_gradient_stop(prim.sub_index + i);
+        vColors[i] = stop.color;
+        vOffsets[i/4][i%4] = stop.offset.x;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_blend.fs.glsl
@@ -0,0 +1,138 @@
+/* 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/. */
+
+vec3 rgbToHsv(vec3 c) {
+    float value = max(max(c.r, c.g), c.b);
+
+    float chroma = value - min(min(c.r, c.g), c.b);
+    if (chroma == 0.0) {
+        return vec3(0.0);
+    }
+    float saturation = chroma / value;
+
+    float hue;
+    if (c.r == value)
+        hue = (c.g - c.b) / chroma;
+    else if (c.g == value)
+        hue = 2.0 + (c.b - c.r) / chroma;
+    else // if (c.b == value)
+        hue = 4.0 + (c.r - c.g) / chroma;
+
+    hue *= 1.0/6.0;
+    if (hue < 0.0)
+        hue += 1.0;
+    return vec3(hue, saturation, value);
+}
+
+vec3 hsvToRgb(vec3 c) {
+    if (c.s == 0.0) {
+        return vec3(c.z);
+    }
+
+    float hue = c.x * 6.0;
+    int sector = int(hue);
+    float residualHue = hue - float(sector);
+
+    vec3 pqt = c.z * vec3(1.0 - c.y, 1.0 - c.y * residualHue, 1.0 - c.y * (1.0 - residualHue));
+    switch (sector) {
+        case 0:
+            return vec3(c.z, pqt.z, pqt.x);
+        case 1:
+            return vec3(pqt.y, c.z, pqt.x);
+        case 2:
+            return vec3(pqt.x, c.z, pqt.z);
+        case 3:
+            return vec3(pqt.x, pqt.y, c.z);
+        case 4:
+            return vec3(pqt.z, pqt.x, c.z);
+        default:
+            return vec3(c.z, pqt.x, pqt.y);
+    }
+}
+
+vec4 Blur(float radius, vec2 direction) {
+    // TODO(gw): Support blur in WR2!
+    return vec4(1.0);
+}
+
+vec4 Contrast(vec4 Cs, float amount) {
+    return vec4(Cs.rgb * amount - 0.5 * amount + 0.5, 1.0);
+}
+
+vec4 Grayscale(vec4 Cs, float amount) {
+    float ia = 1.0 - amount;
+    return mat4(vec4(0.2126 + 0.7874 * ia, 0.2126 - 0.2126 * ia, 0.2126 - 0.2126 * ia, 0.0),
+                vec4(0.7152 - 0.7152 * ia, 0.7152 + 0.2848 * ia, 0.7152 - 0.7152 * ia, 0.0),
+                vec4(0.0722 - 0.0722 * ia, 0.0722 - 0.0722 * ia, 0.0722 + 0.9278 * ia, 0.0),
+                vec4(0.0, 0.0, 0.0, 1.0)) * Cs;
+}
+
+vec4 HueRotate(vec4 Cs, float amount) {
+    vec3 CsHsv = rgbToHsv(Cs.rgb);
+    CsHsv.x = mod(CsHsv.x + amount / 6.283185307179586, 1.0);
+    return vec4(hsvToRgb(CsHsv), Cs.a);
+}
+
+vec4 Invert(vec4 Cs, float amount) {
+    return mix(Cs, vec4(1.0, 1.0, 1.0, Cs.a) - vec4(Cs.rgb, 0.0), amount);
+}
+
+vec4 Saturate(vec4 Cs, float amount) {
+    return vec4(hsvToRgb(min(vec3(1.0, amount, 1.0) * rgbToHsv(Cs.rgb), vec3(1.0))), Cs.a);
+}
+
+vec4 Sepia(vec4 Cs, float amount) {
+    float ia = 1.0 - amount;
+    return mat4(vec4(0.393 + 0.607 * ia, 0.349 - 0.349 * ia, 0.272 - 0.272 * ia, 0.0),
+                vec4(0.769 - 0.769 * ia, 0.686 + 0.314 * ia, 0.534 - 0.534 * ia, 0.0),
+                vec4(0.189 - 0.189 * ia, 0.168 - 0.168 * ia, 0.131 + 0.869 * ia, 0.0),
+                vec4(0.0, 0.0, 0.0, 1.0)) * Cs;
+}
+
+vec4 Brightness(vec4 Cs, float amount) {
+    return vec4(Cs.rgb * amount, Cs.a);
+}
+
+vec4 Opacity(vec4 Cs, float amount) {
+    return vec4(Cs.rgb, Cs.a * amount);
+}
+
+void main(void) {
+    vec4 Cs = texture(sCache, vUv);
+
+    if (Cs.a == 0.0) {
+        discard;
+    }
+
+    switch (vOp) {
+        case 0:
+            // Gaussian blur is specially handled:
+            oFragColor = Cs;// Blur(vAmount, vec2(0,0));
+            break;
+        case 1:
+            oFragColor = Contrast(Cs, vAmount);
+            break;
+        case 2:
+            oFragColor = Grayscale(Cs, vAmount);
+            break;
+        case 3:
+            oFragColor = HueRotate(Cs, vAmount);
+            break;
+        case 4:
+            oFragColor = Invert(Cs, vAmount);
+            break;
+        case 5:
+            oFragColor = Saturate(Cs, vAmount);
+            break;
+        case 6:
+            oFragColor = Sepia(Cs, vAmount);
+            break;
+        case 7:
+            oFragColor = Brightness(Cs, vAmount);
+            break;
+        case 8:
+            oFragColor = Opacity(Cs, vAmount);
+            break;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_blend.glsl
@@ -0,0 +1,7 @@
+/* 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/. */
+
+varying vec3 vUv;
+flat varying float vAmount;
+flat varying int vOp;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_blend.vs.glsl
@@ -0,0 +1,46 @@
+#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/. */
+
+struct Blend {
+    ivec4 src_id_target_id_op_amount;
+    int z;
+};
+
+Blend fetch_blend() {
+    PrimitiveInstance pi = fetch_prim_instance();
+
+    Blend blend;
+    blend.src_id_target_id_op_amount = ivec4(pi.user_data.x,
+                                             pi.render_task_index,
+                                             pi.sub_index,
+                                             pi.user_data.y);
+    blend.z = pi.z;
+
+    return blend;
+}
+
+void main(void) {
+    Blend blend = fetch_blend();
+    Tile src = fetch_tile(blend.src_id_target_id_op_amount.x);
+    Tile dest = fetch_tile(blend.src_id_target_id_op_amount.y);
+
+    vec2 dest_origin = dest.screen_origin_task_origin.zw -
+                       dest.screen_origin_task_origin.xy +
+                       src.screen_origin_task_origin.xy;
+
+    vec2 local_pos = mix(dest_origin,
+                         dest_origin + src.size_target_index.xy,
+                         aPosition.xy);
+
+    vec2 texture_size = vec2(textureSize(sCache, 0));
+    vec2 st0 = src.screen_origin_task_origin.zw / texture_size;
+    vec2 st1 = (src.screen_origin_task_origin.zw + src.size_target_index.xy) / texture_size;
+    vUv = vec3(mix(st0, st1, aPosition.xy), src.size_target_index.z);
+
+    vOp = blend.src_id_target_id_op_amount.z;
+    vAmount = float(blend.src_id_target_id_op_amount.w) / 65535.0;
+
+    gl_Position = uTransform * vec4(local_pos, blend.z, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_border.fs.glsl
@@ -0,0 +1,408 @@
+#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/. */
+
+// Border styles as defined in webrender_traits/types.rs
+#define BORDER_STYLE_NONE         0
+#define BORDER_STYLE_SOLID        1
+#define BORDER_STYLE_DOUBLE       2
+#define BORDER_STYLE_DOTTED       3
+#define BORDER_STYLE_DASHED       4
+#define BORDER_STYLE_HIDDEN       5
+#define BORDER_STYLE_GROOVE       6
+#define BORDER_STYLE_RIDGE        7
+#define BORDER_STYLE_INSET        8
+#define BORDER_STYLE_OUTSET       9
+
+void discard_pixels_in_rounded_borders(vec2 local_pos) {
+  float distanceFromRef = distance(vRefPoint, local_pos);
+  if (vRadii.x > 0.0 && (distanceFromRef > vRadii.x || distanceFromRef < vRadii.z)) {
+      discard;
+  }
+}
+
+vec4 get_fragment_color(float distanceFromMixLine, float pixelsPerFragment) {
+  // Here we are mixing between the two border colors. We need to convert
+  // distanceFromMixLine it to pixel space to properly anti-alias and then push
+  // it between the limits accepted by `mix`.
+  float colorMix = min(max(distanceFromMixLine / pixelsPerFragment, -0.5), 0.5) + 0.5;
+  return mix(vHorizontalColor, vVerticalColor, colorMix);
+}
+
+float alpha_for_solid_border(float distance_from_ref,
+                             float inner_radius,
+                             float outer_radius,
+                             float pixels_per_fragment) {
+  // We want to start anti-aliasing one pixel in from the border.
+  float nudge = pixels_per_fragment;
+  inner_radius += nudge;
+  outer_radius -= nudge;
+
+  if (distance_from_ref < outer_radius && distance_from_ref > inner_radius) {
+    return 1.0;
+  }
+
+  float distance_from_border = max(distance_from_ref - outer_radius,
+                                   inner_radius - distance_from_ref);
+
+  // Move the distance back into pixels.
+  distance_from_border /= pixels_per_fragment;
+
+  // Apply a more gradual fade out to transparent.
+  // distance_from_border -= 0.5;
+
+  return 1.0 - smoothstep(0.0, 1.0, distance_from_border);
+}
+
+float alpha_for_solid_border_corner(vec2 local_pos,
+                                    float inner_radius,
+                                    float outer_radius,
+                                    float pixels_per_fragment) {
+  float distance_from_ref = distance(vRefPoint, local_pos);
+  return alpha_for_solid_border(distance_from_ref, inner_radius, outer_radius, pixels_per_fragment);
+}
+
+vec4 draw_dotted_edge(vec2 local_pos, vec4 piece_rect, float pixels_per_fragment) {
+  // We don't use pixels_per_fragment here, since it can change along the edge
+  // of a transformed border edge. We want this calculation to be consistent
+  // across the entire edge so that the positioning of the dots stays the same.
+  float two_pixels = 2.0 * length(fwidth(vLocalPos.xy));
+
+  // Circle diameter is stroke width, minus a couple pixels to account for anti-aliasing.
+  float circle_diameter = max(piece_rect.z - two_pixels, min(piece_rect.z, two_pixels));
+
+  // We want to spread the circles across the edge, but keep one circle diameter at the end
+  // reserved for two half-circles which connect to the corners.
+  float edge_available = piece_rect.w - (circle_diameter * 2.0);
+  float number_of_circles = floor(edge_available / (circle_diameter * 2.0));
+
+  // Here we are initializing the distance from the y coordinate of the center of the circle to
+  // the closest end half-circle.
+  vec2 relative_pos = local_pos - piece_rect.xy;
+  float y_distance = min(relative_pos.y, piece_rect.w - relative_pos.y);
+
+  if (number_of_circles > 0.0) {
+    // Spread the circles throughout the edge, to distribute the extra space evenly. We want
+    // to ensure that we have at last two pixels of space for each circle so that they aren't
+    // touching.
+    float space_for_each_circle = ceil(max(edge_available / number_of_circles, two_pixels));
+
+    float first_half_circle_space = circle_diameter;
+
+    float circle_index = (relative_pos.y - first_half_circle_space) / space_for_each_circle;
+    circle_index = floor(clamp(circle_index, 0.0, number_of_circles - 1.0));
+
+    float circle_y_pos =
+      circle_index * space_for_each_circle + (space_for_each_circle / 2.0) + circle_diameter;
+    y_distance = min(abs(circle_y_pos - relative_pos.y), y_distance);
+  }
+
+  float distance_from_circle_center = length(vec2(relative_pos.x - (piece_rect.z / 2.0), y_distance));
+  float distance_from_circle_edge = distance_from_circle_center - (circle_diameter / 2.0);
+
+  // Don't anti-alias if the circle diameter is small to avoid a blur of color.
+  if (circle_diameter < two_pixels && distance_from_circle_edge > 0.0)
+    return vec4(0.0);
+
+  // Move the distance back into pixels.
+  distance_from_circle_edge /= pixels_per_fragment;
+
+  float alpha = 1.0 - smoothstep(0.0, 1.0, min(1.0, max(0.0, distance_from_circle_edge)));
+  return vHorizontalColor * vec4(1.0, 1.0, 1.0, alpha);
+}
+
+vec4 draw_dashed_edge(float position, float border_width, float pixels_per_fragment) {
+  // TODO: Investigate exactly what FF does.
+  float size = border_width * 3.0;
+  float segment = floor(position / size);
+
+  float alpha = alpha_for_solid_border(position,
+                                       segment * size,
+                                       (segment + 1.0) * size,
+                                       pixels_per_fragment);
+
+  if (mod(segment + 2.0, 2.0) == 0.0) {
+    return vHorizontalColor * vec4(1.0, 1.0, 1.0, 1.0 - alpha);
+  } else {
+    return vHorizontalColor * vec4(1.0, 1.0, 1.0, alpha);
+  }
+}
+
+void draw_dashed_or_dotted_border(vec2 local_pos, float distance_from_mix_line) {
+  // This is the conversion factor for transformations and device pixel scaling.
+  float pixels_per_fragment = length(fwidth(local_pos.xy));
+
+  switch (vBorderPart) {
+    // These are the layer tile part PrimitivePart as uploaded by the tiling.rs
+    case PST_TOP_LEFT:
+    case PST_TOP_RIGHT:
+    case PST_BOTTOM_LEFT:
+    case PST_BOTTOM_RIGHT:
+    {
+      oFragColor = get_fragment_color(distance_from_mix_line, pixels_per_fragment);
+      if (vRadii.x > 0.0) {
+        oFragColor *= vec4(1.0, 1.0, 1.0, alpha_for_solid_border_corner(local_pos,
+                                                                  vRadii.z,
+                                                                  vRadii.x,
+                                                                  pixels_per_fragment));
+      }
+
+      break;
+    }
+    case PST_BOTTOM:
+    case PST_TOP: {
+      if (vBorderStyle == BORDER_STYLE_DASHED) {
+        oFragColor = draw_dashed_edge(vLocalPos.x - vPieceRect.x,
+                                      vPieceRect.w,
+                                      pixels_per_fragment);
+      } else {
+        oFragColor = draw_dotted_edge(local_pos.yx, vPieceRect.yxwz, pixels_per_fragment);
+      }
+      break;
+    }
+    case PST_LEFT:
+    case PST_RIGHT:
+    {
+      if (vBorderStyle == BORDER_STYLE_DASHED) {
+        oFragColor = draw_dashed_edge(vLocalPos.y - vPieceRect.y,
+                                      vPieceRect.z,
+                                      pixels_per_fragment);
+      } else {
+        oFragColor = draw_dotted_edge(local_pos.xy, vPieceRect.xyzw, pixels_per_fragment);
+      }
+      break;
+    }
+  }
+}
+
+vec4 draw_double_edge(float pos,
+                      float len,
+                      float distance_from_mix_line,
+                      float pixels_per_fragment) {
+  float total_border_width = len;
+  float one_third_width = total_border_width / 3.0;
+
+  // Contribution of the outer border segment.
+  float alpha = alpha_for_solid_border(pos,
+                                       total_border_width - one_third_width,
+                                       total_border_width,
+                                       pixels_per_fragment);
+
+  // Contribution of the inner border segment.
+  alpha += alpha_for_solid_border(pos, 0.0, one_third_width, pixels_per_fragment);
+  return get_fragment_color(distance_from_mix_line, pixels_per_fragment) * vec4(1.0, 1.0, 1.0, alpha);
+}
+
+vec4 draw_double_edge_vertical(vec2 local_pos,
+                               float distance_from_mix_line,
+                               float pixels_per_fragment) {
+  // Get our position within this specific segment
+  float position = local_pos.x - vLocalRect.x;
+  return draw_double_edge(position, vLocalRect.z, distance_from_mix_line, pixels_per_fragment);
+}
+
+vec4 draw_double_edge_horizontal(vec2 local_pos,
+                                 float distance_from_mix_line,
+                                 float pixels_per_fragment) {
+  // Get our position within this specific segment
+  float position = local_pos.y - vLocalRect.y;
+  return draw_double_edge(position, vLocalRect.w, distance_from_mix_line, pixels_per_fragment);
+}
+
+vec4 draw_double_edge_corner_with_radius(vec2 local_pos,
+                                         float distance_from_mix_line,
+                                         float pixels_per_fragment) {
+  float total_border_width = vRadii.x - vRadii.z;
+  float one_third_width = total_border_width / 3.0;
+
+  // Contribution of the outer border segment.
+  float alpha = alpha_for_solid_border_corner(local_pos,
+                                              vRadii.x - one_third_width,
+                                              vRadii.x,
+                                              pixels_per_fragment);
+
+  // Contribution of the inner border segment.
+  alpha += alpha_for_solid_border_corner(local_pos,
+                                         vRadii.z,
+                                         vRadii.z + one_third_width,
+                                         pixels_per_fragment);
+  return get_fragment_color(distance_from_mix_line, pixels_per_fragment) * vec4(1.0, 1.0, 1.0, alpha);
+}
+
+vec4 draw_double_edge_corner(vec2 local_pos,
+                             float distance_from_mix_line,
+                             float pixels_per_fragment) {
+  if (vRadii.x > 0.0) {
+      return draw_double_edge_corner_with_radius(local_pos,
+                                                 distance_from_mix_line,
+                                                 pixels_per_fragment);
+  }
+
+  bool is_vertical = (vBorderPart == PST_TOP_LEFT) ? distance_from_mix_line < 0.0 :
+                                                     distance_from_mix_line >= 0.0;
+  if (is_vertical) {
+    return draw_double_edge_vertical(local_pos, distance_from_mix_line, pixels_per_fragment);
+  } else {
+    return draw_double_edge_horizontal(local_pos, distance_from_mix_line, pixels_per_fragment);
+  }
+}
+
+void draw_double_border(float distance_from_mix_line, vec2 local_pos) {
+  float pixels_per_fragment = length(fwidth(local_pos.xy));
+  switch (vBorderPart) {
+    // These are the layer tile part PrimitivePart as uploaded by the tiling.rs
+    case PST_TOP_LEFT:
+    case PST_TOP_RIGHT:
+    case PST_BOTTOM_LEFT:
+    case PST_BOTTOM_RIGHT:
+    {
+      oFragColor = draw_double_edge_corner(local_pos, distance_from_mix_line, pixels_per_fragment);
+      break;
+    }
+    case PST_BOTTOM:
+    case PST_TOP:
+    {
+      oFragColor = draw_double_edge_horizontal(local_pos,
+                                               distance_from_mix_line,
+                                               pixels_per_fragment);
+      break;
+    }
+    case PST_LEFT:
+    case PST_RIGHT:
+    {
+      oFragColor = draw_double_edge_vertical(local_pos,
+                                             distance_from_mix_line,
+                                             pixels_per_fragment);
+      break;
+    }
+  }
+}
+
+void draw_solid_border(float distanceFromMixLine, vec2 localPos) {
+  switch (vBorderPart) {
+    case PST_TOP_LEFT:
+    case PST_TOP_RIGHT:
+    case PST_BOTTOM_LEFT:
+    case PST_BOTTOM_RIGHT: {
+      // This is the conversion factor for transformations and device pixel scaling.
+      float pixelsPerFragment = length(fwidth(localPos.xy));
+      oFragColor = get_fragment_color(distanceFromMixLine, pixelsPerFragment);
+
+      if (vRadii.x > 0.0) {
+        float alpha = alpha_for_solid_border_corner(localPos, vRadii.z, vRadii.x, pixelsPerFragment);
+        oFragColor *= vec4(1.0, 1.0, 1.0, alpha);
+      }
+
+      break;
+    }
+    default:
+      oFragColor = vHorizontalColor;
+      discard_pixels_in_rounded_borders(localPos);
+  }
+}
+
+vec4 draw_mixed_edge(float distance, float border_len, vec4 color, vec2 brightness_mod) {
+  float modulator = distance / border_len > 0.5 ? brightness_mod.x : brightness_mod.y;
+  return vec4(color.xyz * modulator, color.a);
+}
+
+void draw_mixed_border(float distanceFromMixLine, float distanceFromMiddle, vec2 localPos, vec2 brightness_mod) {
+  switch (vBorderPart) {
+    case PST_TOP_LEFT:
+    case PST_TOP_RIGHT:
+    case PST_BOTTOM_LEFT:
+    case PST_BOTTOM_RIGHT: {
+      // This is the conversion factor for transformations and device pixel scaling.
+      float pixelsPerFragment = length(fwidth(localPos.xy));
+      vec4 color = get_fragment_color(distanceFromMixLine, pixelsPerFragment);
+
+      float distance = distance(vRefPoint, localPos) - vRadii.z;
+      float length = vRadii.x - vRadii.z;
+      if (distanceFromMiddle < 0.0) {
+        distance = length - distance;
+      }
+
+      oFragColor = 0.0 <= distance && distance <= length ?
+        draw_mixed_edge(distance, length, color, brightness_mod) : vec4(0.0, 0.0, 0.0, 0.0);
+      break;
+    }
+    case PST_BOTTOM:
+    case PST_TOP: {
+      oFragColor = draw_mixed_edge(localPos.y - vPieceRect.y, vPieceRect.w, vVerticalColor, brightness_mod);
+      break;
+    }
+    case PST_LEFT:
+    case PST_RIGHT: {
+      oFragColor = draw_mixed_edge(localPos.x - vPieceRect.x, vPieceRect.z, vHorizontalColor, brightness_mod);
+      break;
+    }
+  }
+}
+
+// TODO: Investigate performance of this shader and see
+//       if it's worthwhile splitting it / removing branches etc.
+void main(void) {
+#ifdef WR_FEATURE_TRANSFORM
+    float alpha = 0.0;
+    vec2 local_pos = init_transform_fs(vLocalPos, vLocalRect, alpha);
+#else
+    vec2 local_pos = vLocalPos;
+#endif
+
+#ifdef WR_FEATURE_TRANSFORM
+    // TODO(gw): Support other border styles for transformed elements.
+    float distance_from_mix_line = (local_pos.x - vPieceRect.x) * vPieceRect.w -
+                                   (local_pos.y - vPieceRect.y) * vPieceRect.z;
+    distance_from_mix_line /= vPieceRectHypotenuseLength;
+    float distance_from_middle = (local_pos.x - vLocalRect.x) +
+                                 (local_pos.y - vLocalRect.y) -
+                                 0.5 * (vLocalRect.z + vLocalRect.w);
+#else
+    float distance_from_mix_line = vDistanceFromMixLine;
+    float distance_from_middle = vDistanceFromMiddle;
+#endif
+
+    vec2 brightness_mod = vec2(0.7, 1.3);
+
+    // Note: we can't pass-through in the following cases,
+    // because Angle doesn't support it and fails to compile the shaders.
+    switch (vBorderStyle) {
+        case BORDER_STYLE_DASHED:
+          draw_dashed_or_dotted_border(local_pos, distance_from_mix_line);
+          break;
+        case BORDER_STYLE_DOTTED:
+          draw_dashed_or_dotted_border(local_pos, distance_from_mix_line);
+          break;
+        case BORDER_STYLE_DOUBLE:
+          draw_double_border(distance_from_mix_line, local_pos);
+          break;
+        case BORDER_STYLE_OUTSET:
+          draw_solid_border(distance_from_mix_line, local_pos);
+          break;
+        case BORDER_STYLE_INSET:
+          draw_solid_border(distance_from_mix_line, local_pos);
+          break;
+        case BORDER_STYLE_SOLID:
+          draw_solid_border(distance_from_mix_line, local_pos);
+          break;
+        case BORDER_STYLE_NONE:
+          draw_solid_border(distance_from_mix_line, local_pos);
+          break;
+        case BORDER_STYLE_GROOVE:
+          draw_mixed_border(distance_from_mix_line, distance_from_middle, local_pos, brightness_mod.yx);
+          break;
+        case BORDER_STYLE_RIDGE:
+          draw_mixed_border(distance_from_mix_line, distance_from_middle, local_pos, brightness_mod.xy);
+          break;
+        case BORDER_STYLE_HIDDEN:
+          discard;
+        default:
+          discard;
+    }
+
+#ifdef WR_FEATURE_TRANSFORM
+    oFragColor *= vec4(1.0, 1.0, 1.0, alpha);
+#endif
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_border.glsl
@@ -0,0 +1,33 @@
+#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/. */
+
+// These are not changing.
+flat varying vec4 vVerticalColor;     // The vertical color, e.g. top/bottom
+flat varying vec4 vHorizontalColor;   // The horizontal color e.g. left/right
+flat varying vec4 vRadii;             // The border radius from CSS border-radius
+flat varying vec4 vLocalRect; // The rect of the border (x, y, w, h) in local space.
+
+// for corners, this is the beginning of the corner.
+// For the lines, this is the top left of the line.
+flat varying vec2 vRefPoint;
+flat varying int vBorderStyle;
+flat varying int vBorderPart; // Which part of the border we're drawing.
+
+flat varying vec4 vPieceRect;
+
+// These are in device space
+#ifdef WR_FEATURE_TRANSFORM
+varying vec3 vLocalPos;     // The clamped position in local space.
+flat varying float vPieceRectHypotenuseLength;
+#else
+varying vec2 vLocalPos;     // The clamped position in local space.
+
+// These two are interpolated
+varying float vDistanceFromMixLine;  // This is the distance from the line where two colors
+                                     // meet in border corners.
+varying float vDistanceFromMiddle;   // This is the distance from the line between the top
+                                     // left corner and the bottom right.
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_border.vs.glsl
@@ -0,0 +1,226 @@
+#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/. */
+
+struct Border {
+    vec4 style;
+    vec4 widths;
+    vec4 colors[4];
+    vec4 radii[2];
+};
+
+Border fetch_border(int index) {
+    Border border;
+
+    ivec2 uv = get_fetch_uv_8(index);
+
+    border.style = texelFetchOffset(sData128, uv, 0, ivec2(0, 0));
+    border.widths = texelFetchOffset(sData128, uv, 0, ivec2(1, 0));
+    border.colors[0] = texelFetchOffset(sData128, uv, 0, ivec2(2, 0));
+    border.colors[1] = texelFetchOffset(sData128, uv, 0, ivec2(3, 0));
+    border.colors[2] = texelFetchOffset(sData128, uv, 0, ivec2(4, 0));
+    border.colors[3] = texelFetchOffset(sData128, uv, 0, ivec2(5, 0));
+    border.radii[0] = texelFetchOffset(sData128, uv, 0, ivec2(6, 0));
+    border.radii[1] = texelFetchOffset(sData128, uv, 0, ivec2(7, 0));
+
+    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_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_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_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_inner = bl_outer + vec2(max(border.radii[1].z, border.widths.x),
+                                    -max(border.radii[1].w, border.widths.w));
+
+    vec4 segment_rect;
+    switch (sub_part) {
+        case PST_TOP_LEFT:
+            segment_rect = vec4(tl_outer, 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);
+            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);
+            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);
+            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);
+            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);
+            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);
+            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);
+            vBorderStyle = int(border.style.y);
+            vHorizontalColor = border.colors[BORDER_TOP];
+            vVerticalColor = border.colors[BORDER_TOP];
+            vRadii = vec4(0.0);
+            break;
+    }
+
+#ifdef WR_FEATURE_TRANSFORM
+    TransformVertexInfo vi = write_transform_vertex(segment_rect,
+                                                    prim.local_clip_rect,
+                                                    prim.z,
+                                                    prim.layer,
+                                                    prim.tile);
+    vLocalPos = vi.local_pos;
+
+    // Local space
+    vLocalRect = vi.clipped_local_rect;
+#else
+    VertexInfo vi = write_vertex(segment_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+    vLocalPos = vi.local_clamped_pos.xy;
+
+    // Local space
+    vLocalRect = prim.local_rect;
+#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;
+            // These are width / heights
+            x1 = segment_rect.x + segment_rect.z;
+            y1 = segment_rect.y + segment_rect.w;
+
+            // 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;
+            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;
+            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;
+            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;
+            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;
+
+    vBorderPart = sub_part;
+    vPieceRect = vec4(x0, y0, width, height);
+
+    // The fragment shader needs to calculate the distance from the bisecting line
+    // to properly mix border colors. For transformed borders, we calculate this distance
+    // in the fragment shader itself. For non-transformed borders, we can use the
+    // interpolator.
+#ifdef WR_FEATURE_TRANSFORM
+    vPieceRectHypotenuseLength = sqrt(pow(width, 2.0) + pow(height, 2.0));
+#else
+    vDistanceFromMixLine = (vi.local_clamped_pos.x - x0) * height -
+                           (vi.local_clamped_pos.y - y0) * width;
+    vDistanceFromMiddle = (vi.local_clamped_pos.x - vLocalRect.x) +
+                          (vi.local_clamped_pos.y - vLocalRect.y) -
+                          0.5 * (vLocalRect.z + vLocalRect.w);
+#endif
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_box_shadow.fs.glsl
@@ -0,0 +1,9 @@
+/* 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) {
+    vec2 uv = min(vec2(1.0), vMirrorPoint - abs(vUv.xy - vMirrorPoint));
+    uv = mix(vCacheUvRectCoords.xy, vCacheUvRectCoords.zw, uv);
+    oFragColor = vColor * texture(sCache, vec3(uv, vUv.z));
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_box_shadow.glsl
@@ -0,0 +1,9 @@
+/* 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/. */
+
+flat varying vec4 vColor;
+
+varying vec3 vUv;
+flat varying vec2 vMirrorPoint;
+flat varying vec4 vCacheUvRectCoords;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_box_shadow.vs.glsl
@@ -0,0 +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);
+
+    VertexInfo vi = write_vertex(segment_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+
+    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_clamped_pos - prim.local_rect.xy) / patch_size;
+    vMirrorPoint = 0.5 * prim.local_rect.zw / 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;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_cache_image.fs.glsl
@@ -0,0 +1,7 @@
+/* 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) {
+    oFragColor = texture(sCache, vUv);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_cache_image.glsl
@@ -0,0 +1,5 @@
+/* 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/. */
+
+varying vec3 vUv;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_cache_image.vs.glsl
@@ -0,0 +1,28 @@
+#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/. */
+
+// Draw a cached primitive (e.g. a blurred text run) from the
+// target cache to the framebuffer, applying tile clip boundaries.
+
+void main(void) {
+    Primitive prim = load_primitive();
+
+    VertexInfo vi = write_vertex(prim.local_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+
+    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_clamped_pos - prim.local_rect.xy) / prim.local_rect.zw;
+
+    vUv.xy = mix(uv0, uv1, f);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_clear.fs.glsl
@@ -0,0 +1,7 @@
+/* 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) {
+    oFragColor = vec4(1.0, 1.0, 1.0, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_clear.glsl
@@ -0,0 +1,3 @@
+/* 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/. */
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_clear.vs.glsl
@@ -0,0 +1,14 @@
+#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/. */
+
+in ivec4 aClearRectangle;
+
+void main() {
+    vec4 rect = vec4(aClearRectangle);
+
+    vec4 pos = vec4(mix(rect.xy, rect.xy + rect.zw, aPosition.xy), 0, 1);
+    gl_Position = uTransform * pos;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_composite.fs.glsl
@@ -0,0 +1,219 @@
+#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/. */
+
+float gauss(float x, float sigma) {
+    if (sigma == 0.0)
+        return 1.0;
+    return (1.0 / sqrt(6.283185307179586 * sigma * sigma)) * exp(-(x * x) / (2.0 * sigma * sigma));
+}
+
+vec3 Multiply(vec3 Cb, vec3 Cs) {
+    return Cb * Cs;
+}
+
+vec3 Screen(vec3 Cb, vec3 Cs) {
+    return Cb + Cs - (Cb * Cs);
+}
+
+vec3 HardLight(vec3 Cb, vec3 Cs) {
+    vec3 m = Multiply(Cb, 2.0 * Cs);
+    vec3 s = Screen(Cb, 2.0 * Cs - 1.0);
+    vec3 edge = vec3(0.5, 0.5, 0.5);
+    return mix(m, s, step(edge, Cs));
+}
+
+// TODO: Worth doing with mix/step? Check GLSL output.
+float ColorDodge(float Cb, float Cs) {
+    if (Cb == 0.0)
+        return 0.0;
+    else if (Cs == 1.0)
+        return 1.0;
+    else
+        return min(1.0, Cb / (1.0 - Cs));
+}
+
+// TODO: Worth doing with mix/step? Check GLSL output.
+float ColorBurn(float Cb, float Cs) {
+    if (Cb == 1.0)
+        return 1.0;
+    else if (Cs == 0.0)
+        return 0.0;
+    else
+        return 1.0 - min(1.0, (1.0 - Cb) / Cs);
+}
+
+float SoftLight(float Cb, float Cs) {
+    if (Cs <= 0.5) {
+        return Cb - (1.0 - 2.0 * Cs) * Cb * (1.0 - Cb);
+    } else {
+        float D;
+
+        if (Cb <= 0.25)
+            D = ((16.0 * Cb - 12.0) * Cb + 4.0) * Cb;
+        else
+            D = sqrt(Cb);
+
+        return Cb + (2.0 * Cs - 1.0) * (D - Cb);
+    }
+}
+
+vec3 Difference(vec3 Cb, vec3 Cs) {
+    return abs(Cb - Cs);
+}
+
+vec3 Exclusion(vec3 Cb, vec3 Cs) {
+    return Cb + Cs - 2.0 * Cb * Cs;
+}
+
+// These functions below are taken from the spec.
+// There's probably a much quicker way to implement
+// them in GLSL...
+float Sat(vec3 c) {
+    return max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b));
+}
+
+float Lum(vec3 c) {
+    vec3 f = vec3(0.3, 0.59, 0.11);
+    return dot(c, f);
+}
+
+vec3 ClipColor(vec3 C) {
+    float L = Lum(C);
+    float n = min(C.r, min(C.g, C.b));
+    float x = max(C.r, max(C.g, C.b));
+
+    if (n < 0.0)
+        C = L + (((C - L) * L) / (L - n));
+
+    if (x > 1.0)
+        C = L + (((C - L) * (1.0 - L)) / (x - L));
+
+    return C;
+}
+
+vec3 SetLum(vec3 C, float l) {
+    float d = l - Lum(C);
+    return ClipColor(C + d);
+}
+
+void SetSatInner(inout float Cmin, inout float Cmid, inout float Cmax, float s) {
+    if (Cmax > Cmin) {
+        Cmid = (((Cmid - Cmin) * s) / (Cmax - Cmin));
+        Cmax = s;
+    } else {
+        Cmid = 0.0;
+        Cmax = 0.0;
+    }
+    Cmin = 0.0;
+}
+
+vec3 SetSat(vec3 C, float s) {
+    if (C.r <= C.g) {
+        if (C.g <= C.b) {
+            SetSatInner(C.r, C.g, C.b, s);
+        } else {
+            if (C.r <= C.b) {
+                SetSatInner(C.r, C.b, C.g, s);
+            } else {
+                SetSatInner(C.b, C.r, C.g, s);
+            }
+        }
+    } else {
+        if (C.r <= C.b) {
+            SetSatInner(C.g, C.r, C.b, s);
+        } else {
+            if (C.g <= C.b) {
+                SetSatInner(C.g, C.b, C.r, s);
+            } else {
+                SetSatInner(C.b, C.g, C.r, s);
+            }
+        }
+    }
+    return C;
+}
+
+vec3 Hue(vec3 Cb, vec3 Cs) {
+    return SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb));
+}
+
+vec3 Saturation(vec3 Cb, vec3 Cs) {
+    return SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb));
+}
+
+vec3 Color(vec3 Cb, vec3 Cs) {
+    return SetLum(Cs, Lum(Cb));
+}
+
+vec3 Luminosity(vec3 Cb, vec3 Cs) {
+    return SetLum(Cb, Lum(Cs));
+}
+
+void main(void) {
+    vec4 Cb = texture(sCache, vUv0);
+
+    if (vUv1.x < vUv1Rect.x ||
+        vUv1.x > vUv1Rect.z ||
+        vUv1.y < vUv1Rect.y ||
+        vUv1.y > vUv1Rect.w) {
+        oFragColor = Cb;
+        return;
+    }
+
+    vec4 Cs = texture(sCache, vUv1);
+
+    // Return yellow if none of the branches match (shouldn't happen).
+    vec4 result = vec4(1.0, 1.0, 0.0, 1.0);
+
+    switch (vOp) {
+        case 1:
+            result.rgb = Multiply(Cb.rgb, Cs.rgb);
+            break;
+        case 2:
+            result.rgb = Screen(Cb.rgb, Cs.rgb);
+            break;
+        case 3:
+            result.rgb = HardLight(Cs.rgb, Cb.rgb);        // Overlay is inverse of Hardlight
+            break;
+        case 6:
+            result.r = ColorDodge(Cb.r, Cs.r);
+            result.g = ColorDodge(Cb.g, Cs.g);
+            result.b = ColorDodge(Cb.b, Cs.b);
+            break;
+        case 7:
+            result.r = ColorBurn(Cb.r, Cs.r);
+            result.g = ColorBurn(Cb.g, Cs.g);
+            result.b = ColorBurn(Cb.b, Cs.b);
+            break;
+        case 8:
+            result.rgb = HardLight(Cb.rgb, Cs.rgb);
+            break;
+        case 9:
+            result.r = SoftLight(Cb.r, Cs.r);
+            result.g = SoftLight(Cb.g, Cs.g);
+            result.b = SoftLight(Cb.b, Cs.b);
+            break;
+        case 10:
+            result.rgb = Difference(Cb.rgb, Cs.rgb);
+            break;
+        case 11:
+            result.rgb = Exclusion(Cb.rgb, Cs.rgb);
+            break;
+        case 12:
+            result.rgb = Hue(Cb.rgb, Cs.rgb);
+            break;
+        case 13:
+            result.rgb = Saturation(Cb.rgb, Cs.rgb);
+            break;
+        case 14:
+            result.rgb = Color(Cb.rgb, Cs.rgb);
+            break;
+        case 15:
+            result.rgb = Luminosity(Cb.rgb, Cs.rgb);
+            break;
+    }
+
+    oFragColor = result;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_composite.glsl
@@ -0,0 +1,8 @@
+/* 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/. */
+
+varying vec3 vUv0;
+varying vec3 vUv1;
+flat varying vec4 vUv1Rect;
+flat varying int vOp;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_composite.vs.glsl
@@ -0,0 +1,50 @@
+#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/. */
+
+struct Composite {
+    ivec4 src0_src1_target_id_op;
+    int z;
+};
+
+Composite fetch_composite() {
+    PrimitiveInstance pi = fetch_prim_instance();
+
+    Composite composite;
+    composite.src0_src1_target_id_op = ivec4(pi.user_data.xy,
+                                             pi.render_task_index,
+                                             pi.sub_index);
+    composite.z = pi.z;
+
+    return composite;
+}
+
+void main(void) {
+    Composite composite = fetch_composite();
+    Tile src0 = fetch_tile(composite.src0_src1_target_id_op.x);
+    Tile src1 = fetch_tile(composite.src0_src1_target_id_op.y);
+    Tile dest = fetch_tile(composite.src0_src1_target_id_op.z);
+
+    vec2 local_pos = mix(dest.screen_origin_task_origin.zw,
+                         dest.screen_origin_task_origin.zw + dest.size_target_index.xy,
+                         aPosition.xy);
+
+    vec2 texture_size = vec2(textureSize(sCache, 0));
+    vec2 st0 = src0.screen_origin_task_origin.zw / texture_size;
+    vec2 st1 = (src0.screen_origin_task_origin.zw + src0.size_target_index.xy) / texture_size;
+    vUv0 = vec3(mix(st0, st1, aPosition.xy), src0.size_target_index.z);
+
+    st0 = vec2(src1.screen_origin_task_origin.zw) / texture_size;
+    st1 = vec2(src1.screen_origin_task_origin.zw + src1.size_target_index.xy) / texture_size;
+    vec2 local_virtual_pos = mix(dest.screen_origin_task_origin.xy,
+                                 dest.screen_origin_task_origin.xy + dest.size_target_index.xy,
+                                 aPosition.xy);
+    vec2 f = (local_virtual_pos - src1.screen_origin_task_origin.xy) / src1.size_target_index.xy;
+    vUv1 = vec3(mix(st0, st1, f), src1.size_target_index.z);
+    vUv1Rect = vec4(st0, st1);
+
+    vOp = composite.src0_src1_target_id_op.w;
+
+    gl_Position = uTransform * vec4(local_pos, composite.z, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_gradient.fs.glsl
@@ -0,0 +1,16 @@
+/* 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) {
+#ifdef WR_FEATURE_TRANSFORM
+    float alpha = 0.0;
+    vec2 local_pos = init_transform_fs(vLocalPos, vLocalRect, alpha);
+#else
+    float alpha = 1.0;
+    vec2 local_pos = vPos;
+#endif
+
+    alpha = min(alpha, do_clip());
+    oFragColor = vColor * vec4(1.0, 1.0, 1.0, alpha);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_gradient.glsl
@@ -0,0 +1,12 @@
+/* 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/. */
+
+varying vec4 vColor;
+
+#ifdef WR_FEATURE_TRANSFORM
+varying vec3 vLocalPos;
+flat varying vec4 vLocalRect;
+#else
+varying vec2 vPos;
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_gradient.vs.glsl
@@ -0,0 +1,72 @@
+#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();
+    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;
+    switch (int(gradient.kind.x)) {
+        case GRADIENT_HORIZONTAL: {
+            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;
+            } break;
+        case GRADIENT_VERTICAL: {
+            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;
+            } break;
+    }
+
+#ifdef WR_FEATURE_TRANSFORM
+    TransformVertexInfo vi = write_transform_vertex(segment_rect,
+                                                    prim.local_clip_rect,
+                                                    prim.z,
+                                                    prim.layer,
+                                                    prim.tile);
+    vLocalRect = vi.clipped_local_rect;
+    vLocalPos = vi.local_pos;
+    vec2 f = (vi.local_pos.xy - prim.local_rect.xy) / prim.local_rect.zw;
+#else
+    VertexInfo vi = write_vertex(segment_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+
+    vec2 f = (vi.local_clamped_pos - segment_rect.xy) / segment_rect.zw;
+    vPos = vi.local_clamped_pos;
+#endif
+
+    write_clip(vi.global_clamped_pos, prim.clip_area);
+
+    switch (int(gradient.kind.x)) {
+        case GRADIENT_HORIZONTAL:
+            vColor = mix(g0.color, g1.color, f.x);
+            break;
+        case GRADIENT_VERTICAL:
+            vColor = mix(g0.color, g1.color, f.y);
+            break;
+        case GRADIENT_ROTATED:
+            vColor = vec4(1.0, 0.0, 1.0, 1.0);
+            break;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_image.fs.glsl
@@ -0,0 +1,31 @@
+#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) {
+#ifdef WR_FEATURE_TRANSFORM
+    float alpha = 0.0;
+    vec2 pos = init_transform_fs(vLocalPos, vLocalRect, alpha);
+
+    // We clamp the texture coordinate calculation here to the local rectangle boundaries,
+    // which makes the edge of the texture stretch instead of repeat.
+    vec2 relative_pos_in_rect =
+         clamp(pos, vLocalRect.xy, vLocalRect.xy + vLocalRect.zw) - vLocalRect.xy;
+#else
+    float alpha = 1.0;
+    vec2 relative_pos_in_rect = vLocalPos;
+#endif
+
+    alpha = min(alpha, do_clip());
+
+    // We calculate the particular tile this fragment belongs to, taking into
+    // account the spacing in between tiles. We only paint if our fragment does
+    // not fall into that spacing.
+    vec2 position_in_tile = mod(relative_pos_in_rect, vStretchSize + vTileSpacing);
+    vec2 st = vTextureOffset + ((position_in_tile / vStretchSize) * vTextureSize);
+    alpha = alpha * float(all(bvec2(step(position_in_tile, vStretchSize))));
+
+    oFragColor = vec4(1.0, 1.0, 1.0, alpha) * texture(sColor0, st);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_image.glsl
@@ -0,0 +1,16 @@
+/* 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/. */
+
+flat varying vec2 vTextureOffset; // Offset of this image into the texture atlas.
+flat varying vec2 vTextureSize;   // Size of the image in the texture atlas.
+flat varying vec2 vTileSpacing;   // Amount of space between tiled instances of this image.
+
+#ifdef WR_FEATURE_TRANSFORM
+varying vec3 vLocalPos;
+flat varying vec4 vLocalRect;
+flat varying vec2 vStretchSize;
+#else
+varying vec2 vLocalPos;
+flat varying vec2 vStretchSize;
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_image.vs.glsl
@@ -0,0 +1,39 @@
+#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();
+    Image image = fetch_image(prim.prim_index);
+    ResourceRect res = fetch_resource_rect(prim.user_data.x);
+
+#ifdef WR_FEATURE_TRANSFORM
+    TransformVertexInfo vi = write_transform_vertex(prim.local_rect,
+                                                    prim.local_clip_rect,
+                                                    prim.z,
+                                                    prim.layer,
+                                                    prim.tile);
+    vLocalRect = vi.clipped_local_rect;
+    vLocalPos = vi.local_pos;
+#else
+    VertexInfo vi = write_vertex(prim.local_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+    vLocalPos = vi.local_clamped_pos - vi.local_rect.p0;
+#endif
+
+    write_clip(vi.global_clamped_pos, prim.clip_area);
+
+    // vUv will contain how many times this image has wrapped around the image size.
+    vec2 texture_size = vec2(textureSize(sColor0, 0));
+    vec2 st0 = res.uv_rect.xy / texture_size;
+    vec2 st1 = res.uv_rect.zw / texture_size;
+
+    vTextureSize = st1 - st0;
+    vTextureOffset = st0;
+    vTileSpacing = image.stretch_size_and_tile_spacing.zw;
+    vStretchSize = image.stretch_size_and_tile_spacing.xy;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_radial_gradient.fs.glsl
@@ -0,0 +1,67 @@
+/* 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/. */
+
+float offset(int index) {
+    return vOffsets[index / 4][index % 4];
+}
+
+float linearStep(float lo, float hi, float x) {
+    float d = hi - lo;
+    float v = x - lo;
+    if (d != 0.0) {
+        v /= d;
+    }
+    return clamp(v, 0.0, 1.0);
+}
+
+void main(void) {
+    vec2 cd = vEndCenter - vStartCenter;
+    vec2 pd = vPos - vStartCenter;
+    float rd = vEndRadius - vStartRadius;
+
+    // Solve for t in length(t * cd - pd) = vStartRadius + t * rd
+    // using a quadratic equation in form of At^2 - 2Bt + C = 0
+    float A = dot(cd, cd) - rd * rd;
+    float B = dot(pd, cd) + vStartRadius * rd;
+    float C = dot(pd, pd) - vStartRadius * vStartRadius;
+
+    float x;
+    if (A == 0.0) {
+        // Since A is 0, just solve for -2Bt + C = 0
+        if (B == 0.0) {
+            discard;
+        }
+        float t = 0.5 * C / B;
+        if (vStartRadius + rd * t >= 0.0) {
+            x = t;
+        } else {
+            discard;
+        }
+    } else {
+        float discr = B * B - A * C;
+        if (discr < 0.0) {
+            discard;
+        }
+        discr = sqrt(discr);
+        float t0 = (B + discr) / A;
+        float t1 = (B - discr) / A;
+        if (vStartRadius + rd * t0 >= 0.0) {
+            x = t0;
+        } else if (vStartRadius + rd * t1 >= 0.0) {
+            x = t1;
+        } else {
+            discard;
+        }
+    }
+
+    oFragColor = mix(vColors[0],
+                     vColors[1],
+                     linearStep(offset(0), offset(1), x));
+
+    for (int i=1 ; i < vStopCount-1 ; ++i) {
+        oFragColor = mix(oFragColor,
+                         vColors[i+1],
+                         linearStep(offset(i), offset(i+1), x));
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_radial_gradient.glsl
@@ -0,0 +1,12 @@
+/* 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/. */
+
+flat varying int vStopCount;
+flat varying vec2 vStartCenter;
+flat varying vec2 vEndCenter;
+flat varying float vStartRadius;
+flat varying float vEndRadius;
+varying vec2 vPos;
+flat varying vec4 vColors[MAX_STOPS_PER_RADIAL_GRADIENT];
+flat varying vec4 vOffsets[MAX_STOPS_PER_RADIAL_GRADIENT/4];
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_radial_gradient.vs.glsl
@@ -0,0 +1,35 @@
+#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();
+    RadialGradient gradient = fetch_radial_gradient(prim.prim_index);
+
+    VertexInfo vi = write_vertex(prim.local_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+
+    vStopCount = int(prim.user_data.x);
+    vPos = vi.local_clamped_pos;
+
+    // Snap the start/end points to device pixel units.
+    // I'm not sure this is entirely correct, but the
+    // old render path does this, and it is needed to
+    // make the angle gradient ref tests pass. It might
+    // be better to fix this higher up in DL construction
+    // and not snap here?
+    vStartCenter = floor(0.5 + gradient.start_end_center.xy * uDevicePixelRatio) / uDevicePixelRatio;
+    vEndCenter = floor(0.5 + gradient.start_end_center.zw * uDevicePixelRatio) / uDevicePixelRatio;
+    vStartRadius = gradient.start_end_radius.x;
+    vEndRadius = gradient.start_end_radius.y;
+
+    for (int i=0 ; i < vStopCount ; ++i) {
+        GradientStop stop = fetch_gradient_stop(prim.sub_index + i);
+        vColors[i] = stop.color;
+        vOffsets[i/4][i%4] = stop.offset.x;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_rectangle.fs.glsl
@@ -0,0 +1,16 @@
+/* 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) {
+    float alpha = 1.0;
+#ifdef WR_FEATURE_TRANSFORM
+    alpha = 0.0;
+    init_transform_fs(vLocalPos, vLocalRect, alpha);
+#endif
+
+#ifdef WR_FEATURE_CLIP
+    alpha = min(alpha, do_clip());
+#endif
+    oFragColor = vColor * vec4(1.0, 1.0, 1.0, alpha);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_rectangle.glsl
@@ -0,0 +1,10 @@
+/* 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/. */
+
+varying vec4 vColor;
+
+#ifdef WR_FEATURE_TRANSFORM
+varying vec3 vLocalPos;
+flat varying vec4 vLocalRect;
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_rectangle.vs.glsl
@@ -0,0 +1,29 @@
+#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();
+    Rectangle rect = fetch_rectangle(prim.prim_index);
+    vColor = rect.color;
+#ifdef WR_FEATURE_TRANSFORM
+    TransformVertexInfo vi = write_transform_vertex(prim.local_rect,
+                                                    prim.local_clip_rect,
+                                                    prim.z,
+                                                    prim.layer,
+                                                    prim.tile);
+    vLocalRect = vi.clipped_local_rect;
+    vLocalPos = vi.local_pos;
+#else
+    VertexInfo vi = write_vertex(prim.local_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+#endif
+
+#ifdef WR_FEATURE_CLIP
+    write_clip(vi.global_clamped_pos, prim.clip_area);
+#endif
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_text_run.fs.glsl
@@ -0,0 +1,20 @@
+/* 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) {
+#ifdef WR_FEATURE_SUBPIXEL_AA
+    //note: the blend mode is not compatible with clipping
+    oFragColor = texture(sColor0, vUv);
+#else
+    float alpha = texture(sColor0, vUv).a;
+#ifdef WR_FEATURE_TRANSFORM
+    float a = 0.0;
+    init_transform_fs(vLocalPos, vLocalRect, a);
+    alpha *= a;
+#endif
+    vec4 color = vColor;
+    alpha = min(alpha, do_clip());
+    oFragColor = vec4(vColor.rgb, vColor.a * alpha);
+#endif
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_text_run.glsl
@@ -0,0 +1,11 @@
+/* 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/. */
+
+flat varying vec4 vColor;
+varying vec2 vUv;
+
+#ifdef WR_FEATURE_TRANSFORM
+varying vec3 vLocalPos;
+flat varying vec4 vLocalRect;
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_text_run.vs.glsl
@@ -0,0 +1,40 @@
+#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();
+    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);
+
+#ifdef WR_FEATURE_TRANSFORM
+    TransformVertexInfo vi = write_transform_vertex(local_rect,
+                                                    prim.local_clip_rect,
+                                                    prim.z,
+                                                    prim.layer,
+                                                    prim.tile);
+    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;
+#else
+    VertexInfo vi = write_vertex(local_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+    vec2 f = (vi.local_clamped_pos - vi.local_rect.p0) / (vi.local_rect.p1 - vi.local_rect.p0);
+#endif
+
+    write_clip(vi.global_clamped_pos, prim.clip_area);
+
+    vec2 texture_size = vec2(textureSize(sColor0, 0));
+    vec2 st0 = res.uv_rect.xy / texture_size;
+    vec2 st1 = res.uv_rect.zw / texture_size;
+
+    vColor = text.color;
+    vUv = mix(st0, st1, f);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_yuv_image.fs.glsl
@@ -0,0 +1,33 @@
+#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) {
+#ifdef WR_FEATURE_TRANSFORM
+    float alpha = 0.0;
+    vec2 pos = init_transform_fs(vLocalPos, vLocalRect, alpha);
+
+    // We clamp the texture coordinate calculation here to the local rectangle boundaries,
+    // which makes the edge of the texture stretch instead of repeat.
+    vec2 relative_pos_in_rect =
+         clamp(pos, vLocalRect.xy, vLocalRect.xy + vLocalRect.zw) - vLocalRect.xy;
+#else
+    float alpha = 1.0;;
+    vec2 relative_pos_in_rect = vLocalPos;
+#endif
+
+    alpha = min(alpha, do_clip());
+
+    vec2 st_y = vTextureOffsetY + relative_pos_in_rect / vStretchSize * vTextureSizeY;
+    vec2 st_u = vTextureOffsetU + relative_pos_in_rect / vStretchSize * vTextureSizeUv;
+    vec2 st_v = vTextureOffsetV + relative_pos_in_rect / vStretchSize * vTextureSizeUv;
+
+    float y = texture(sColor0, st_y).r;
+    float u = texture(sColor1, st_u).r;
+    float v = texture(sColor2, st_v).r;
+
+    // See the vertex shader for an explanation of where the constants come from.
+    vec3 rgb = vYuvColorMatrix * vec3(y - 0.06275, u - 0.50196, v - 0.50196);
+    oFragColor = vec4(rgb, alpha);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_yuv_image.glsl
@@ -0,0 +1,19 @@
+/* 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/. */
+
+flat varying vec2 vTextureOffsetY; // Offset of the y plane into the texture atlas.
+flat varying vec2 vTextureOffsetU; // Offset of the u plane into the texture atlas.
+flat varying vec2 vTextureOffsetV; // Offset of the v plane into the texture atlas.
+flat varying vec2 vTextureSizeY;   // Size of the y plane in the texture atlas.
+flat varying vec2 vTextureSizeUv;  // Size of the u and v planes in the texture atlas.
+flat varying vec2 vStretchSize;
+
+flat varying mat3 vYuvColorMatrix;
+
+#ifdef WR_FEATURE_TRANSFORM
+varying vec3 vLocalPos;
+flat varying vec4 vLocalRect;
+#else
+varying vec2 vLocalPos;
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_yuv_image.vs.glsl
@@ -0,0 +1,77 @@
+#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();
+#ifdef WR_FEATURE_TRANSFORM
+    TransformVertexInfo vi = write_transform_vertex(prim.local_rect,
+                                                    prim.local_clip_rect,
+                                                    prim.z,
+                                                    prim.layer,
+                                                    prim.tile);
+    vLocalRect = vi.clipped_local_rect;
+    vLocalPos = vi.local_pos;
+#else
+    VertexInfo vi = write_vertex(prim.local_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+    vLocalPos = vi.local_clamped_pos - vi.local_rect.p0;
+#endif
+
+    YuvImage image = fetch_yuv_image(prim.prim_index);
+
+    vec2 y_texture_size = vec2(textureSize(sColor0, 0));
+    vec2 y_st0 = image.y_st_rect.xy / y_texture_size;
+    vec2 y_st1 = image.y_st_rect.zw / y_texture_size;
+
+    vTextureSizeY = y_st1 - y_st0;
+    vTextureOffsetY = y_st0;
+
+    vec2 uv_texture_size = vec2(textureSize(sColor1, 0));
+    vec2 u_st0 = image.u_st_rect.xy / uv_texture_size;
+    vec2 u_st1 = image.u_st_rect.zw / uv_texture_size;
+
+    vec2 v_st0 = image.v_st_rect.xy / uv_texture_size;
+    vec2 v_st1 = image.v_st_rect.zw / uv_texture_size;
+
+    // This assumes the U and V surfaces have the same size.
+    vTextureSizeUv = u_st1 - u_st0;
+    vTextureOffsetU = u_st0;
+    vTextureOffsetV = v_st0;
+
+    vStretchSize = image.size;
+
+    // The constants added to the Y, U and V components are applied in the fragment shader.
+    if (image.color_space == YUV_REC601) {
+        // From Rec601:
+        // [R]   [1.1643835616438356,  0.0,                 1.5960267857142858   ]   [Y -  16]
+        // [G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708   ] x [U - 128]
+        // [B]   [1.1643835616438356,  2.017232142857143,   8.862867620416422e-17]   [V - 128]
+        //
+        // For the range [0,1] instead of [0,255].
+        vYuvColorMatrix = mat3(
+            1.16438,  0.0,      1.59603,
+            1.16438, -0.39176, -0.81297,
+            1.16438,  2.01723,  0.0
+        );
+    } else { // if (image.color_space == YUV_REC709)
+        // From Rec709:
+        // [R]   [1.1643835616438356,  4.2781193979771426e-17, 1.7927410714285714]   [Y -  16]
+        // [G] = [1.1643835616438358, -0.21324861427372963,   -0.532909328559444 ] x [U - 128]
+        // [B]   [1.1643835616438356,  2.1124017857142854,     0.0               ]   [V - 128]
+        //
+        // For the range [0,1] instead of [0,255]:
+        vYuvColorMatrix = mat3(
+            1.16438,  0.0,      1.79274,
+            1.16438, -0.21325, -0.53291,
+            1.16438,  2.11240,  0.0
+        );
+    }
+
+    write_clip(vi.global_clamped_pos, prim.clip_area);
+
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/shared.glsl
@@ -0,0 +1,51 @@
+/* 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/. */
+
+//======================================================================================
+// Vertex shader attributes and uniforms
+//======================================================================================
+#ifdef WR_VERTEX_SHADER
+    #define varying out
+
+    // Uniform inputs
+    uniform mat4 uTransform;       // Orthographic projection
+    uniform float uDevicePixelRatio;
+
+    // Attribute inputs
+    in vec3 aPosition;
+#endif
+
+//======================================================================================
+// Fragment shader attributes and uniforms
+//======================================================================================
+#ifdef WR_FRAGMENT_SHADER
+    precision highp float;
+
+    #define varying in
+
+    // Uniform inputs
+
+    // Fragment shader outputs
+    out vec4 oFragColor;
+#endif
+
+//======================================================================================
+// Shared shader uniforms
+//======================================================================================
+uniform sampler2D sColor0;
+uniform sampler2D sColor1;
+uniform sampler2D sColor2;
+uniform sampler2D sMask;
+
+//======================================================================================
+// Interpolator definitions
+//======================================================================================
+
+//======================================================================================
+// VS only types and UBOs
+//======================================================================================
+
+//======================================================================================
+// VS only functions
+//======================================================================================
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/shared_other.glsl
@@ -0,0 +1,33 @@
+/* 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/. */
+
+//======================================================================================
+// Vertex shader attributes and uniforms
+//======================================================================================
+#ifdef WR_VERTEX_SHADER
+#endif
+
+//======================================================================================
+// Fragment shader attributes and uniforms
+//======================================================================================
+#ifdef WR_FRAGMENT_SHADER
+#endif
+
+//======================================================================================
+// Interpolator definitions
+//======================================================================================
+
+//======================================================================================
+// VS only types and UBOs
+//======================================================================================
+
+//======================================================================================
+// VS only functions
+//======================================================================================
+
+//======================================================================================
+// FS only functions
+//======================================================================================
+#ifdef WR_FRAGMENT_SHADER
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/src/batch_builder.rs
@@ -0,0 +1,43 @@
+/* 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 std::f32;
+use webrender_traits::{ColorF, BorderStyle};
+use webrender_traits::{BorderSide};
+
+//const BORDER_DASH_SIZE: f32 = 3.0;
+
+pub trait BorderSideHelpers {
+    fn border_color(&self,
+                    scale_factor_0: f32,
+                    scale_factor_1: f32,
+                    black_color_0: f32,
+                    black_color_1: f32) -> ColorF;
+}
+
+impl BorderSideHelpers for BorderSide {
+    fn border_color(&self,
+                    scale_factor_0: f32,
+                    scale_factor_1: f32,
+                    black_color_0: f32,
+                    black_color_1: f32) -> ColorF {
+        match self.style {
+            BorderStyle::Inset => {
+                if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 {
+                    self.color.scale_rgb(scale_factor_1)
+                } else {
+                    ColorF::new(black_color_0, black_color_0, black_color_0, self.color.a)
+                }
+            }
+            BorderStyle::Outset => {
+                if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 {
+                    self.color.scale_rgb(scale_factor_0)
+                } else {
+                    ColorF::new(black_color_1, black_color_1, black_color_1, self.color.a)
+                }
+            }
+            _ => self.color,
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/src/debug_colors.rs
@@ -0,0 +1,158 @@
+/* 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/. */
+
+#![allow(dead_code)]
+
+use webrender_traits::ColorF;
+
+// A subset of the standard CSS colors, useful for defining GPU tag colors etc.
+
+pub const INDIGO: ColorF = ColorF { r: 0.294117647059, g: 0.0, b: 0.509803921569, a: 1.0 };
+pub const GOLD: ColorF = ColorF { r: 1.0, g: 0.843137254902, b: 0.0, a: 1.0 };
+pub const FIREBRICK: ColorF = ColorF { r: 0.698039215686, g: 0.133333333333, b: 0.133333333333, a: 1.0 };
+pub const INDIANRED: ColorF = ColorF { r: 0.803921568627, g: 0.360784313725, b: 0.360784313725, a: 1.0 };
+pub const YELLOW: ColorF = ColorF { r: 1.0, g: 1.0, b: 0.0, a: 1.0 };
+pub const DARKOLIVEGREEN: ColorF = ColorF { r: 0.333333333333, g: 0.419607843137, b: 0.18431372549, a: 1.0 };
+pub const DARKSEAGREEN: ColorF = ColorF { r: 0.560784313725, g: 0.737254901961, b: 0.560784313725, a: 1.0 };
+pub const SLATEGREY: ColorF = ColorF { r: 0.439215686275, g: 0.501960784314, b: 0.564705882353, a: 1.0 };
+pub const DARKSLATEGREY: ColorF = ColorF { r: 0.18431372549, g: 0.309803921569, b: 0.309803921569, a: 1.0 };
+pub const MEDIUMVIOLETRED: ColorF = ColorF { r: 0.780392156863, g: 0.0823529411765, b: 0.521568627451, a: 1.0 };
+pub const MEDIUMORCHID: ColorF = ColorF { r: 0.729411764706, g: 0.333333333333, b: 0.827450980392, a: 1.0 };
+pub const CHARTREUSE: ColorF = ColorF { r: 0.498039215686, g: 1.0, b: 0.0, a: 1.0 };
+pub const MEDIUMSLATEBLUE: ColorF = ColorF { r: 0.482352941176, g: 0.407843137255, b: 0.933333333333, a: 1.0 };
+pub const BLACK: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.0, a: 1.0 };
+pub const SPRINGGREEN: ColorF = ColorF { r: 0.0, g: 1.0, b: 0.498039215686, a: 1.0 };
+pub const CRIMSON: ColorF = ColorF { r: 0.862745098039, g: 0.078431372549, b: 0.235294117647, a: 1.0 };
+pub const LIGHTSALMON: ColorF = ColorF { r: 1.0, g: 0.627450980392, b: 0.478431372549, a: 1.0 };
+pub const BROWN: ColorF = ColorF { r: 0.647058823529, g: 0.164705882353, b: 0.164705882353, a: 1.0 };
+pub const TURQUOISE: ColorF = ColorF { r: 0.250980392157, g: 0.878431372549, b: 0.81568627451, a: 1.0 };
+pub const OLIVEDRAB: ColorF = ColorF { r: 0.419607843137, g: 0.556862745098, b: 0.137254901961, a: 1.0 };
+pub const CYAN: ColorF = ColorF { r: 0.0, g: 1.0, b: 1.0, a: 1.0 };
+pub const SILVER: ColorF = ColorF { r: 0.752941176471, g: 0.752941176471, b: 0.752941176471, a: 1.0 };
+pub const SKYBLUE: ColorF = ColorF { r: 0.529411764706, g: 0.807843137255, b: 0.921568627451, a: 1.0 };
+pub const GRAY: ColorF = ColorF { r: 0.501960784314, g: 0.501960784314, b: 0.501960784314, a: 1.0 };
+pub const DARKTURQUOISE: ColorF = ColorF { r: 0.0, g: 0.807843137255, b: 0.819607843137, a: 1.0 };
+pub const GOLDENROD: ColorF = ColorF { r: 0.854901960784, g: 0.647058823529, b: 0.125490196078, a: 1.0 };
+pub const DARKGREEN: ColorF = ColorF { r: 0.0, g: 0.392156862745, b: 0.0, a: 1.0 };
+pub const DARKVIOLET: ColorF = ColorF { r: 0.580392156863, g: 0.0, b: 0.827450980392, a: 1.0 };
+pub const DARKGRAY: ColorF = ColorF { r: 0.662745098039, g: 0.662745098039, b: 0.662745098039, a: 1.0 };
+pub const LIGHTPINK: ColorF = ColorF { r: 1.0, g: 0.713725490196, b: 0.756862745098, a: 1.0 };
+pub const TEAL: ColorF = ColorF { r: 0.0, g: 0.501960784314, b: 0.501960784314, a: 1.0 };
+pub const DARKMAGENTA: ColorF = ColorF { r: 0.545098039216, g: 0.0, b: 0.545098039216, a: 1.0 };
+pub const LIGHTGOLDENRODYELLOW: ColorF = ColorF { r: 0.980392156863, g: 0.980392156863, b: 0.823529411765, a: 1.0 };
+pub const LAVENDER: ColorF = ColorF { r: 0.901960784314, g: 0.901960784314, b: 0.980392156863, a: 1.0 };
+pub const YELLOWGREEN: ColorF = ColorF { r: 0.603921568627, g: 0.803921568627, b: 0.196078431373, a: 1.0 };
+pub const THISTLE: ColorF = ColorF { r: 0.847058823529, g: 0.749019607843, b: 0.847058823529, a: 1.0 };
+pub const VIOLET: ColorF = ColorF { r: 0.933333333333, g: 0.509803921569, b: 0.933333333333, a: 1.0 };
+pub const NAVY: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.501960784314, a: 1.0 };
+pub const DIMGREY: ColorF = ColorF { r: 0.411764705882, g: 0.411764705882, b: 0.411764705882, a: 1.0 };
+pub const ORCHID: ColorF = ColorF { r: 0.854901960784, g: 0.439215686275, b: 0.839215686275, a: 1.0 };
+pub const BLUE: ColorF = ColorF { r: 0.0, g: 0.0, b: 1.0, a: 1.0 };
+pub const GHOSTWHITE: ColorF = ColorF { r: 0.972549019608, g: 0.972549019608, b: 1.0, a: 1.0 };
+pub const HONEYDEW: ColorF = ColorF { r: 0.941176470588, g: 1.0, b: 0.941176470588, a: 1.0 };
+pub const CORNFLOWERBLUE: ColorF = ColorF { r: 0.392156862745, g: 0.58431372549, b: 0.929411764706, a: 1.0 };
+pub const DARKBLUE: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.545098039216, a: 1.0 };
+pub const DARKKHAKI: ColorF = ColorF { r: 0.741176470588, g: 0.717647058824, b: 0.419607843137, a: 1.0 };
+pub const MEDIUMPURPLE: ColorF = ColorF { r: 0.576470588235, g: 0.439215686275, b: 0.858823529412, a: 1.0 };
+pub const CORNSILK: ColorF = ColorF { r: 1.0, g: 0.972549019608, b: 0.862745098039, a: 1.0 };
+pub const RED: ColorF = ColorF { r: 1.0, g: 0.0, b: 0.0, a: 1.0 };
+pub const BISQUE: ColorF = ColorF { r: 1.0, g: 0.894117647059, b: 0.76862745098, a: 1.0 };
+pub const SLATEGRAY: ColorF = ColorF { r: 0.439215686275, g: 0.501960784314, b: 0.564705882353, a: 1.0 };
+pub const DARKCYAN: ColorF = ColorF { r: 0.0, g: 0.545098039216, b: 0.545098039216, a: 1.0 };
+pub const KHAKI: ColorF = ColorF { r: 0.941176470588, g: 0.901960784314, b: 0.549019607843, a: 1.0 };
+pub const WHEAT: ColorF = ColorF { r: 0.960784313725, g: 0.870588235294, b: 0.701960784314, a: 1.0 };
+pub const DEEPSKYBLUE: ColorF = ColorF { r: 0.0, g: 0.749019607843, b: 1.0, a: 1.0 };
+pub const REBECCAPURPLE: ColorF = ColorF { r: 0.4, g: 0.2, b: 0.6, a: 1.0 };
+pub const DARKRED: ColorF = ColorF { r: 0.545098039216, g: 0.0, b: 0.0, a: 1.0 };
+pub const STEELBLUE: ColorF = ColorF { r: 0.274509803922, g: 0.509803921569, b: 0.705882352941, a: 1.0 };
+pub const ALICEBLUE: ColorF = ColorF { r: 0.941176470588, g: 0.972549019608, b: 1.0, a: 1.0 };
+pub const LIGHTSLATEGREY: ColorF = ColorF { r: 0.466666666667, g: 0.533333333333, b: 0.6, a: 1.0 };
+pub const GAINSBORO: ColorF = ColorF { r: 0.862745098039, g: 0.862745098039, b: 0.862745098039, a: 1.0 };
+pub const MEDIUMTURQUOISE: ColorF = ColorF { r: 0.282352941176, g: 0.819607843137, b: 0.8, a: 1.0 };
+pub const FLORALWHITE: ColorF = ColorF { r: 1.0, g: 0.980392156863, b: 0.941176470588, a: 1.0 };
+pub const CORAL: ColorF = ColorF { r: 1.0, g: 0.498039215686, b: 0.313725490196, a: 1.0 };
+pub const PURPLE: ColorF = ColorF { r: 0.501960784314, g: 0.0, b: 0.501960784314, a: 1.0 };
+pub const LIGHTGREY: ColorF = ColorF { r: 0.827450980392, g: 0.827450980392, b: 0.827450980392, a: 1.0 };
+pub const LIGHTCYAN: ColorF = ColorF { r: 0.878431372549, g: 1.0, b: 1.0, a: 1.0 };
+pub const DARKSALMON: ColorF = ColorF { r: 0.913725490196, g: 0.588235294118, b: 0.478431372549, a: 1.0 };
+pub const BEIGE: ColorF = ColorF { r: 0.960784313725, g: 0.960784313725, b: 0.862745098039, a: 1.0 };
+pub const AZURE: ColorF = ColorF { r: 0.941176470588, g: 1.0, b: 1.0, a: 1.0 };
+pub const LIGHTSTEELBLUE: ColorF = ColorF { r: 0.690196078431, g: 0.76862745098, b: 0.870588235294, a: 1.0 };
+pub const OLDLACE: ColorF = ColorF { r: 0.992156862745, g: 0.960784313725, b: 0.901960784314, a: 1.0 };
+pub const GREENYELLOW: ColorF = ColorF { r: 0.678431372549, g: 1.0, b: 0.18431372549, a: 1.0 };
+pub const ROYALBLUE: ColorF = ColorF { r: 0.254901960784, g: 0.411764705882, b: 0.882352941176, a: 1.0 };
+pub const LIGHTSEAGREEN: ColorF = ColorF { r: 0.125490196078, g: 0.698039215686, b: 0.666666666667, a: 1.0 };
+pub const MISTYROSE: ColorF = ColorF { r: 1.0, g: 0.894117647059, b: 0.882352941176, a: 1.0 };
+pub const SIENNA: ColorF = ColorF { r: 0.627450980392, g: 0.321568627451, b: 0.176470588235, a: 1.0 };
+pub const LIGHTCORAL: ColorF = ColorF { r: 0.941176470588, g: 0.501960784314, b: 0.501960784314, a: 1.0 };
+pub const ORANGERED: ColorF = ColorF { r: 1.0, g: 0.270588235294, b: 0.0, a: 1.0 };
+pub const NAVAJOWHITE: ColorF = ColorF { r: 1.0, g: 0.870588235294, b: 0.678431372549, a: 1.0 };
+pub const LIME: ColorF = ColorF { r: 0.0, g: 1.0, b: 0.0, a: 1.0 };
+pub const PALEGREEN: ColorF = ColorF { r: 0.596078431373, g: 0.98431372549, b: 0.596078431373, a: 1.0 };
+pub const BURLYWOOD: ColorF = ColorF { r: 0.870588235294, g: 0.721568627451, b: 0.529411764706, a: 1.0 };
+pub const SEASHELL: ColorF = ColorF { r: 1.0, g: 0.960784313725, b: 0.933333333333, a: 1.0 };
+pub const MEDIUMSPRINGGREEN: ColorF = ColorF { r: 0.0, g: 0.980392156863, b: 0.603921568627, a: 1.0 };
+pub const FUCHSIA: ColorF = ColorF { r: 1.0, g: 0.0, b: 1.0, a: 1.0 };
+pub const PAPAYAWHIP: ColorF = ColorF { r: 1.0, g: 0.937254901961, b: 0.835294117647, a: 1.0 };
+pub const BLANCHEDALMOND: ColorF = ColorF { r: 1.0, g: 0.921568627451, b: 0.803921568627, a: 1.0 };
+pub const PERU: ColorF = ColorF { r: 0.803921568627, g: 0.521568627451, b: 0.247058823529, a: 1.0 };
+pub const AQUAMARINE: ColorF = ColorF { r: 0.498039215686, g: 1.0, b: 0.83137254902, a: 1.0 };
+pub const WHITE: ColorF = ColorF { r: 1.0, g: 1.0, b: 1.0, a: 1.0 };
+pub const DARKSLATEGRAY: ColorF = ColorF { r: 0.18431372549, g: 0.309803921569, b: 0.309803921569, a: 1.0 };
+pub const TOMATO: ColorF = ColorF { r: 1.0, g: 0.388235294118, b: 0.278431372549, a: 1.0 };
+pub const IVORY: ColorF = ColorF { r: 1.0, g: 1.0, b: 0.941176470588, a: 1.0 };
+pub const DODGERBLUE: ColorF = ColorF { r: 0.117647058824, g: 0.564705882353, b: 1.0, a: 1.0 };
+pub const LEMONCHIFFON: ColorF = ColorF { r: 1.0, g: 0.980392156863, b: 0.803921568627, a: 1.0 };
+pub const CHOCOLATE: ColorF = ColorF { r: 0.823529411765, g: 0.411764705882, b: 0.117647058824, a: 1.0 };
+pub const ORANGE: ColorF = ColorF { r: 1.0, g: 0.647058823529, b: 0.0, a: 1.0 };
+pub const FORESTGREEN: ColorF = ColorF { r: 0.133333333333, g: 0.545098039216, b: 0.133333333333, a: 1.0 };
+pub const DARKGREY: ColorF = ColorF { r: 0.662745098039, g: 0.662745098039, b: 0.662745098039, a: 1.0 };
+pub const OLIVE: ColorF = ColorF { r: 0.501960784314, g: 0.501960784314, b: 0.0, a: 1.0 };
+pub const MINTCREAM: ColorF = ColorF { r: 0.960784313725, g: 1.0, b: 0.980392156863, a: 1.0 };
+pub const ANTIQUEWHITE: ColorF = ColorF { r: 0.980392156863, g: 0.921568627451, b: 0.843137254902, a: 1.0 };
+pub const DARKORANGE: ColorF = ColorF { r: 1.0, g: 0.549019607843, b: 0.0, a: 1.0 };
+pub const CADETBLUE: ColorF = ColorF { r: 0.372549019608, g: 0.619607843137, b: 0.627450980392, a: 1.0 };
+pub const MOCCASIN: ColorF = ColorF { r: 1.0, g: 0.894117647059, b: 0.709803921569, a: 1.0 };
+pub const LIMEGREEN: ColorF = ColorF { r: 0.196078431373, g: 0.803921568627, b: 0.196078431373, a: 1.0 };
+pub const SADDLEBROWN: ColorF = ColorF { r: 0.545098039216, g: 0.270588235294, b: 0.0745098039216, a: 1.0 };
+pub const GREY: ColorF = ColorF { r: 0.501960784314, g: 0.501960784314, b: 0.501960784314, a: 1.0 };
+pub const DARKSLATEBLUE: ColorF = ColorF { r: 0.282352941176, g: 0.239215686275, b: 0.545098039216, a: 1.0 };
+pub const LIGHTSKYBLUE: ColorF = ColorF { r: 0.529411764706, g: 0.807843137255, b: 0.980392156863, a: 1.0 };
+pub const DEEPPINK: ColorF = ColorF { r: 1.0, g: 0.078431372549, b: 0.576470588235, a: 1.0 };
+pub const PLUM: ColorF = ColorF { r: 0.866666666667, g: 0.627450980392, b: 0.866666666667, a: 1.0 };
+pub const AQUA: ColorF = ColorF { r: 0.0, g: 1.0, b: 1.0, a: 1.0 };
+pub const DARKGOLDENROD: ColorF = ColorF { r: 0.721568627451, g: 0.525490196078, b: 0.043137254902, a: 1.0 };
+pub const MAROON: ColorF = ColorF { r: 0.501960784314, g: 0.0, b: 0.0, a: 1.0 };
+pub const SANDYBROWN: ColorF = ColorF { r: 0.956862745098, g: 0.643137254902, b: 0.376470588235, a: 1.0 };
+pub const MAGENTA: ColorF = ColorF { r: 1.0, g: 0.0, b: 1.0, a: 1.0 };
+pub const TAN: ColorF = ColorF { r: 0.823529411765, g: 0.705882352941, b: 0.549019607843, a: 1.0 };
+pub const ROSYBROWN: ColorF = ColorF { r: 0.737254901961, g: 0.560784313725, b: 0.560784313725, a: 1.0 };
+pub const PINK: ColorF = ColorF { r: 1.0, g: 0.752941176471, b: 0.796078431373, a: 1.0 };
+pub const LIGHTBLUE: ColorF = ColorF { r: 0.678431372549, g: 0.847058823529, b: 0.901960784314, a: 1.0 };
+pub const PALEVIOLETRED: ColorF = ColorF { r: 0.858823529412, g: 0.439215686275, b: 0.576470588235, a: 1.0 };
+pub const MEDIUMSEAGREEN: ColorF = ColorF { r: 0.235294117647, g: 0.701960784314, b: 0.443137254902, a: 1.0 };
+pub const SLATEBLUE: ColorF = ColorF { r: 0.41568627451, g: 0.352941176471, b: 0.803921568627, a: 1.0 };
+pub const DIMGRAY: ColorF = ColorF { r: 0.411764705882, g: 0.411764705882, b: 0.411764705882, a: 1.0 };
+pub const POWDERBLUE: ColorF = ColorF { r: 0.690196078431, g: 0.878431372549, b: 0.901960784314, a: 1.0 };
+pub const SEAGREEN: ColorF = ColorF { r: 0.180392156863, g: 0.545098039216, b: 0.341176470588, a: 1.0 };
+pub const SNOW: ColorF = ColorF { r: 1.0, g: 0.980392156863, b: 0.980392156863, a: 1.0 };
+pub const MEDIUMBLUE: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.803921568627, a: 1.0 };
+pub const MIDNIGHTBLUE: ColorF = ColorF { r: 0.0980392156863, g: 0.0980392156863, b: 0.439215686275, a: 1.0 };
+pub const PALETURQUOISE: ColorF = ColorF { r: 0.686274509804, g: 0.933333333333, b: 0.933333333333, a: 1.0 };
+pub const PALEGOLDENROD: ColorF = ColorF { r: 0.933333333333, g: 0.909803921569, b: 0.666666666667, a: 1.0 };
+pub const WHITESMOKE: ColorF = ColorF { r: 0.960784313725, g: 0.960784313725, b: 0.960784313725, a: 1.0 };
+pub const DARKORCHID: ColorF = ColorF { r: 0.6, g: 0.196078431373, b: 0.8, a: 1.0 };
+pub const SALMON: ColorF = ColorF { r: 0.980392156863, g: 0.501960784314, b: 0.447058823529, a: 1.0 };
+pub const LIGHTSLATEGRAY: ColorF = ColorF { r: 0.466666666667, g: 0.533333333333, b: 0.6, a: 1.0 };
+pub const LAWNGREEN: ColorF = ColorF { r: 0.486274509804, g: 0.988235294118, b: 0.0, a: 1.0 };
+pub const LIGHTGREEN: ColorF = ColorF { r: 0.564705882353, g: 0.933333333333, b: 0.564705882353, a: 1.0 };
+pub const LIGHTGRAY: ColorF = ColorF { r: 0.827450980392, g: 0.827450980392, b: 0.827450980392, a: 1.0 };
+pub const HOTPINK: ColorF = ColorF { r: 1.0, g: 0.411764705882, b: 0.705882352941, a: 1.0 };
+pub const LIGHTYELLOW: ColorF = ColorF { r: 1.0, g: 1.0, b: 0.878431372549, a: 1.0 };
+pub const LAVENDERBLUSH: ColorF = ColorF { r: 1.0, g: 0.941176470588, b: 0.960784313725, a: 1.0 };
+pub const LINEN: ColorF = ColorF { r: 0.980392156863, g: 0.941176470588, b: 0.901960784314, a: 1.0 };
+pub const MEDIUMAQUAMARINE: ColorF = ColorF { r: 0.4, g: 0.803921568627, b: 0.666666666667, a: 1.0 };
+pub const GREEN: ColorF = ColorF { r: 0.0, g: 0.501960784314, b: 0.0, a: 1.0 };
+pub const BLUEVIOLET: ColorF = ColorF { r: 0.541176470588, g: 0.16862745098, b: 0.886274509804, a: 1.0 };
+pub const PEACHPUFF: ColorF = ColorF { r: 1.0, g: 0.854901960784, b: 0.725490196078, a: 1.0 };
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/src/debug_font_data.rs
@@ -0,0 +1,1914 @@
+/* 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/. */
+
+#[derive(Debug)]
+pub struct BakedGlyph {
+    pub x0: u32,
+    pub y0: u32,
+    pub x1: u32,
+    pub y1: u32,
+    pub xo: f32,
+    pub yo: f32,
+    pub xa: f32,
+}
+
+pub const FIRST_GLYPH_INDEX: u32 = 32;
+pub const BMP_WIDTH: u32 = 128;
+pub const BMP_HEIGHT: u32 = 128;
+pub const FONT_SIZE: u32 = 19;
+
+pub const GLYPHS: [BakedGlyph; 96] = [
+    BakedGlyph {
+        x0: 1,
+        y0: 1,
+        x1: 1,
+        y1: 1,
+        xo: 0.000000,
+        yo: 0.000000,
+        xa: 3.864407,
+    },
+    BakedGlyph {
+        x0: 2,
+        y0: 1,
+        x1: 5,
+        y1: 14,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 4.644068,
+    },
+    BakedGlyph {
+        x0: 6,
+        y0: 1,
+        x1: 11,
+        y1: 6,
+        xo: 1.000000,
+        yo: -13.000000,
+        xa: 6.644068,
+    },
+    BakedGlyph {
+        x0: 12,
+        y0: 1,
+        x1: 23,
+        y1: 13,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 11.067797,
+    },
+    BakedGlyph {
+        x0: 24,
+        y0: 1,
+        x1: 32,
+        y1: 17,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 33,
+        y0: 1,
+        x1: 46,
+        y1: 14,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 14.084745,
+    },
+    BakedGlyph {
+        x0: 47,
+        y0: 1,
+        x1: 58,
+        y1: 14,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 10.983051,
+    },
+    BakedGlyph {
+        x0: 59,
+        y0: 1,
+        x1: 61,
+        y1: 6,
+        xo: 1.000000,
+        yo: -13.000000,
+        xa: 4.067797,
+    },
+    BakedGlyph {
+        x0: 62,
+        y0: 1,
+        x1: 67,
+        y1: 19,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 5.254237,
+    },
+    BakedGlyph {
+        x0: 68,
+        y0: 1,
+        x1: 72,
+        y1: 19,
+        xo: 0.000000,
+        yo: -14.000000,
+        xa: 5.254237,
+    },
+    BakedGlyph {
+        x0: 73,
+        y0: 1,
+        x1: 81,
+        y1: 8,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 8.000000,
+    },
+    BakedGlyph {
+        x0: 82,
+        y0: 1,
+        x1: 91,
+        y1: 11,
+        xo: 0.000000,
+        yo: -10.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 92,
+        y0: 1,
+        x1: 95,
+        y1: 6,
+        xo: 0.000000,
+        yo: -2.000000,
+        xa: 4.169492,
+    },
+    BakedGlyph {
+        x0: 96,
+        y0: 1,
+        x1: 101,
+        y1: 3,
+        xo: 0.000000,
+        yo: -6.000000,
+        xa: 4.779661,
+    },
+    BakedGlyph {
+        x0: 102,
+        y0: 1,
+        x1: 105,
+        y1: 4,
+        xo: 1.000000,
+        yo: -2.000000,
+        xa: 4.169492,
+    },
+    BakedGlyph {
+        x0: 106,
+        y0: 1,
+        x1: 114,
+        y1: 19,
+        xo: -1.000000,
+        yo: -14.000000,
+        xa: 6.084746,
+    },
+    BakedGlyph {
+        x0: 115,
+        y0: 1,
+        x1: 123,
+        y1: 14,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 1,
+        y0: 20,
+        x1: 6,
+        y1: 32,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 7,
+        y0: 20,
+        x1: 15,
+        y1: 32,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 16,
+        y0: 20,
+        x1: 24,
+        y1: 33,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 25,
+        y0: 20,
+        x1: 34,
+        y1: 32,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 35,
+        y0: 20,
+        x1: 43,
+        y1: 33,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 44,
+        y0: 20,
+        x1: 52,
+        y1: 33,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 53,
+        y0: 20,
+        x1: 61,
+        y1: 32,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 62,
+        y0: 20,
+        x1: 70,
+        y1: 33,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 71,
+        y0: 20,
+        x1: 79,
+        y1: 33,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 80,
+        y0: 20,
+        x1: 83,
+        y1: 30,
+        xo: 1.000000,
+        yo: -9.000000,
+        xa: 4.169492,
+    },
+    BakedGlyph {
+        x0: 84,
+        y0: 20,
+        x1: 88,
+        y1: 32,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 4.169492,
+    },
+    BakedGlyph {
+        x0: 89,
+        y0: 20,
+        x1: 98,
+        y1: 28,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 99,
+        y0: 20,
+        x1: 108,
+        y1: 26,
+        xo: 0.000000,
+        yo: -8.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 109,
+        y0: 20,
+        x1: 118,
+        y1: 28,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 119,
+        y0: 20,
+        x1: 125,
+        y1: 33,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 6.440678,
+    },
+    BakedGlyph {
+        x0: 1,
+        y0: 34,
+        x1: 15,
+        y1: 49,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 15.932203,
+    },
+    BakedGlyph {
+        x0: 16,
+        y0: 34,
+        x1: 27,
+        y1: 46,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 10.864407,
+    },
+    BakedGlyph {
+        x0: 28,
+        y0: 34,
+        x1: 37,
+        y1: 47,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 10.677966,
+    },
+    BakedGlyph {
+        x0: 38,
+        y0: 34,
+        x1: 47,
+        y1: 47,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 10.322034,
+    },
+    BakedGlyph {
+        x0: 48,
+        y0: 34,
+        x1: 58,
+        y1: 47,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 11.898305,
+    },
+    BakedGlyph {
+        x0: 59,
+        y0: 34,
+        x1: 67,
+        y1: 46,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.406779,
+    },
+    BakedGlyph {
+        x0: 68,
+        y0: 34,
+        x1: 76,
+        y1: 46,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 8.813560,
+    },
+    BakedGlyph {
+        x0: 77,
+        y0: 34,
+        x1: 86,
+        y1: 47,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 11.152542,
+    },
+    BakedGlyph {
+        x0: 87,
+        y0: 34,
+        x1: 97,
+        y1: 46,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 11.728813,
+    },
+    BakedGlyph {
+        x0: 98,
+        y0: 34,
+        x1: 100,
+        y1: 46,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 4.203390,
+    },
+    BakedGlyph {
+        x0: 101,
+        y0: 34,
+        x1: 108,
+        y1: 47,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 8.254237,
+    },
+    BakedGlyph {
+        x0: 109,
+        y0: 34,
+        x1: 118,
+        y1: 46,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 10.152542,
+    },
+    BakedGlyph {
+        x0: 1,
+        y0: 50,
+        x1: 9,
+        y1: 62,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 8.508474,
+    },
+    BakedGlyph {
+        x0: 10,
+        y0: 50,
+        x1: 23,
+        y1: 62,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 14.661017,
+    },
+    BakedGlyph {
+        x0: 24,
+        y0: 50,
+        x1: 34,
+        y1: 62,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 12.016949,
+    },
+    BakedGlyph {
+        x0: 35,
+        y0: 50,
+        x1: 47,
+        y1: 63,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 13.118644,
+    },
+    BakedGlyph {
+        x0: 48,
+        y0: 50,
+        x1: 57,
+        y1: 62,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 10.033898,
+    },
+    BakedGlyph {
+        x0: 58,
+        y0: 50,
+        x1: 70,
+        y1: 66,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 13.118644,
+    },
+    BakedGlyph {
+        x0: 71,
+        y0: 50,
+        x1: 81,
+        y1: 62,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 10.474576,
+    },
+    BakedGlyph {
+        x0: 82,
+        y0: 50,
+        x1: 91,
+        y1: 63,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 8.762712,
+    },
+    BakedGlyph {
+        x0: 92,
+        y0: 50,
+        x1: 101,
+        y1: 62,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 9.288136,
+    },
+    BakedGlyph {
+        x0: 102,
+        y0: 50,
+        x1: 112,
+        y1: 63,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 11.525424,
+    },
+    BakedGlyph {
+        x0: 113,
+        y0: 50,
+        x1: 124,
+        y1: 62,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 10.576271,
+    },
+    BakedGlyph {
+        x0: 1,
+        y0: 67,
+        x1: 16,
+        y1: 79,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 15.610169,
+    },
+    BakedGlyph {
+        x0: 17,
+        y0: 67,
+        x1: 27,
+        y1: 79,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 10.305085,
+    },
+    BakedGlyph {
+        x0: 28,
+        y0: 67,
+        x1: 38,
+        y1: 79,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 9.644068,
+    },
+    BakedGlyph {
+        x0: 39,
+        y0: 67,
+        x1: 48,
+        y1: 79,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 9.491526,
+    },
+    BakedGlyph {
+        x0: 49,
+        y0: 67,
+        x1: 54,
+        y1: 85,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 5.254237,
+    },
+    BakedGlyph {
+        x0: 55,
+        y0: 67,
+        x1: 63,
+        y1: 85,
+        xo: -1.000000,
+        yo: -14.000000,
+        xa: 6.084746,
+    },
+    BakedGlyph {
+        x0: 64,
+        y0: 67,
+        x1: 68,
+        y1: 85,
+        xo: 0.000000,
+        yo: -14.000000,
+        xa: 5.254237,
+    },
+    BakedGlyph {
+        x0: 69,
+        y0: 67,
+        x1: 77,
+        y1: 74,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 78,
+        y0: 67,
+        x1: 88,
+        y1: 69,
+        xo: -1.000000,
+        yo: 2.000000,
+        xa: 8.305085,
+    },
+    BakedGlyph {
+        x0: 89,
+        y0: 67,
+        x1: 93,
+        y1: 72,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 6.372881,
+    },
+    BakedGlyph {
+        x0: 94,
+        y0: 67,
+        x1: 102,
+        y1: 77,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 8.627119,
+    },
+    BakedGlyph {
+        x0: 103,
+        y0: 67,
+        x1: 111,
+        y1: 82,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 9.881356,
+    },
+    BakedGlyph {
+        x0: 112,
+        y0: 67,
+        x1: 120,
+        y1: 77,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 7.796610,
+    },
+    BakedGlyph {
+        x0: 1,
+        y0: 86,
+        x1: 10,
+        y1: 101,
+        xo: 0.000000,
+        yo: -14.000000,
+        xa: 9.881356,
+    },
+    BakedGlyph {
+        x0: 11,
+        y0: 86,
+        x1: 20,
+        y1: 96,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 9.288136,
+    },
+    BakedGlyph {
+        x0: 21,
+        y0: 86,
+        x1: 27,
+        y1: 100,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 6.372881,
+    },
+    BakedGlyph {
+        x0: 28,
+        y0: 86,
+        x1: 37,
+        y1: 99,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 9.711864,
+    },
+    BakedGlyph {
+        x0: 38,
+        y0: 86,
+        x1: 46,
+        y1: 100,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 9.644068,
+    },
+    BakedGlyph {
+        x0: 47,
+        y0: 86,
+        x1: 49,
+        y1: 99,
+        xo: 1.000000,
+        yo: -13.000000,
+        xa: 4.016949,
+    },
+    BakedGlyph {
+        x0: 50,
+        y0: 86,
+        x1: 55,
+        y1: 103,
+        xo: -2.000000,
+        yo: -13.000000,
+        xa: 4.016949,
+    },
+    BakedGlyph {
+        x0: 56,
+        y0: 86,
+        x1: 64,
+        y1: 100,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 8.389831,
+    },
+    BakedGlyph {
+        x0: 65,
+        y0: 86,
+        x1: 68,
+        y1: 101,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 4.322034,
+    },
+    BakedGlyph {
+        x0: 69,
+        y0: 86,
+        x1: 82,
+        y1: 95,
+        xo: 1.000000,
+        yo: -9.000000,
+        xa: 14.627119,
+    },
+    BakedGlyph {
+        x0: 83,
+        y0: 86,
+        x1: 91,
+        y1: 95,
+        xo: 1.000000,
+        yo: -9.000000,
+        xa: 9.644068,
+    },
+    BakedGlyph {
+        x0: 92,
+        y0: 86,
+        x1: 101,
+        y1: 96,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 9.864407,
+    },
+    BakedGlyph {
+        x0: 102,
+        y0: 86,
+        x1: 110,
+        y1: 99,
+        xo: 1.000000,
+        yo: -9.000000,
+        xa: 9.881356,
+    },
+    BakedGlyph {
+        x0: 111,
+        y0: 86,
+        x1: 120,
+        y1: 99,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 9.881356,
+    },
+    BakedGlyph {
+        x0: 1,
+        y0: 104,
+        x1: 7,
+        y1: 113,
+        xo: 1.000000,
+        yo: -9.000000,
+        xa: 6.338983,
+    },
+    BakedGlyph {
+        x0: 8,
+        y0: 104,
+        x1: 15,
+        y1: 114,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 7.254237,
+    },
+    BakedGlyph {
+        x0: 16,
+        y0: 104,
+        x1: 22,
+        y1: 117,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 6.559322,
+    },
+    BakedGlyph {
+        x0: 23,
+        y0: 104,
+        x1: 31,
+        y1: 114,
+        xo: 1.000000,
+        yo: -9.000000,
+        xa: 9.644068,
+    },
+    BakedGlyph {
+        x0: 32,
+        y0: 104,
+        x1: 40,
+        y1: 113,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 8.135593,
+    },
+    BakedGlyph {
+        x0: 41,
+        y0: 104,
+        x1: 54,
+        y1: 113,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 13.135593,
+    },
+    BakedGlyph {
+        x0: 55,
+        y0: 104,
+        x1: 63,
+        y1: 113,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 8.457627,
+    },
+    BakedGlyph {
+        x0: 64,
+        y0: 104,
+        x1: 72,
+        y1: 117,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 8.033898,
+    },
+    BakedGlyph {
+        x0: 73,
+        y0: 104,
+        x1: 81,
+        y1: 113,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 7.711864,
+    },
+    BakedGlyph {
+        x0: 82,
+        y0: 104,
+        x1: 88,
+        y1: 122,
+        xo: 0.000000,
+        yo: -14.000000,
+        xa: 5.406780,
+    },
+    BakedGlyph {
+        x0: 89,
+        y0: 104,
+        x1: 91,
+        y1: 122,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 4.440678,
+    },
+    BakedGlyph {
+        x0: 92,
+        y0: 104,
+        x1: 97,
+        y1: 122,
+        xo: 0.000000,
+        yo: -14.000000,
+        xa: 5.406780,
+    },
+    BakedGlyph {
+        x0: 98,
+        y0: 104,
+        x1: 107,
+        y1: 108,
+        xo: 0.000000,
+        yo: -7.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 108,
+        y0: 104,
+        x1: 116,
+        y1: 117,
+        xo: 0.000000,
+        yo: -13.000000,
+        xa: 8.474576,
+    },
+];
+
+pub const FONT_BITMAP: [u8; 16384] = [
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x34,0xae,0x00,0x00,0x81,0x90,0x00,0xe0,0x31,0x00,0x00,0x00,0x00,0x06,
+    0xba,0x05,0x00,0x00,0xa2,0x23,0x00,0x00,0x00,0x00,0x00,0x1a,0x0d,0x00,0x00,0x00,
+    0x00,0x16,0xb2,0xec,0xbc,0x1f,0x00,0x00,0x00,0x49,0x8c,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x0d,0x9d,0xeb,0xe5,0x89,0x03,0x00,0x00,0x00,0x00,0x81,0x90,0x00,0x00,0x00,
+    0x00,0x13,0x00,0x00,0x11,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0x6b,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x04,0x00,0x00,0x00,0x00,0x00,0x4a,0x76,0x00,
+    0x3b,0x70,0x70,0x70,0x22,0x00,0x56,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x2d,0x1e,0x00,0x00,0x18,0xac,0xea,0xd2,0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x45,0xe9,0x00,0x00,0x8a,0x99,0x00,0xf6,0x2d,0x00,0x00,0x00,0x00,0x2f,
+    0xd8,0x00,0x00,0x08,0xf7,0x09,0x00,0x00,0x00,0x00,0x00,0xad,0x52,0x00,0x00,0x00,
+    0x00,0xa5,0x8f,0x0c,0x7d,0xba,0x00,0x00,0x06,0xda,0x3d,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x92,0xb9,0x20,0x28,0xd7,0x64,0x00,0x00,0x00,0x00,0x8a,0x99,0x00,0x00,0x00,
+    0x28,0xdd,0x03,0x00,0xa5,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x7f,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0xb6,0x45,0x00,0x00,0x00,0x00,0x00,0x80,0xaa,0x00,
+    0x54,0xa0,0xa0,0xa0,0x31,0x00,0xbb,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+    0xe0,0x34,0x00,0x0b,0xd7,0x95,0x1d,0x40,0xe1,0x6d,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x45,0xe9,0x00,0x00,0x7a,0x88,0x00,0xe6,0x1c,0x00,0x00,0x00,0x00,0x60,
+    0xa8,0x00,0x00,0x34,0xd3,0x00,0x00,0x00,0x00,0x00,0x00,0xb2,0x6b,0x0b,0x00,0x00,
+    0x00,0xea,0x22,0x00,0x10,0xf7,0x05,0x00,0x73,0xab,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0xd6,0x50,0x00,0x00,0x81,0x98,0x00,0x00,0x00,0x00,0x7a,0x88,0x00,0x00,0x00,
+    0xb4,0x6a,0x00,0x00,0x2e,0xe4,0x0d,0x00,0x00,0x24,0xcd,0x61,0x65,0x62,0x61,0xcd,
+    0x24,0x00,0x00,0x00,0x00,0x00,0xb6,0x45,0x00,0x00,0x00,0x00,0x00,0x9b,0x83,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,
+    0xda,0x00,0x00,0x5e,0xd0,0x03,0x00,0x00,0x49,0xe6,0x04,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x44,0xe9,0x00,0x00,0x5a,0x67,0x00,0xbf,0x02,0x00,0x1b,0x86,0x86,0xc4,
+    0xc5,0x86,0x86,0xb0,0xd9,0x86,0x24,0x00,0x00,0x57,0xc9,0xea,0xd3,0xef,0x85,0x00,
+    0x00,0xed,0x1e,0x00,0x0d,0xf7,0x07,0x15,0xe8,0x21,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0xbf,0x65,0x00,0x00,0xc6,0x6a,0x00,0x00,0x00,0x00,0x5a,0x67,0x00,0x00,0x47,
+    0xd7,0x04,0x00,0x00,0x00,0x9d,0x85,0x00,0x00,0x0d,0x55,0x8d,0xcc,0xcc,0x8c,0x54,
+    0x0d,0x00,0x00,0x00,0x00,0x00,0xb6,0x45,0x00,0x00,0x00,0x00,0x01,0xe0,0x2e,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x96,
+    0x81,0x00,0x00,0xb7,0x80,0x00,0x00,0x00,0x04,0xf1,0x45,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x3d,0xe3,0x00,0x00,0x0f,0x12,0x00,0x21,0x00,0x00,0x13,0x5f,0x5f,0xe0,
+    0x86,0x5f,0x5f,0xc2,0x9f,0x5f,0x1a,0x00,0x16,0xf9,0x3d,0x01,0x00,0x03,0x13,0x00,
+    0x00,0xae,0x80,0x04,0x6c,0xc4,0x00,0x96,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x56,0xe2,0x1f,0x8e,0xc2,0x06,0x00,0x00,0x00,0x00,0x0f,0x12,0x00,0x00,0xc7,
+    0x4f,0x00,0x00,0x00,0x00,0x1a,0xee,0x0d,0x00,0x00,0x00,0x3b,0xb4,0xb5,0x37,0x00,
+    0x00,0x00,0x05,0x5f,0x5f,0x5f,0xd1,0x8a,0x5f,0x5f,0x3a,0x00,0x0b,0x76,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xea,
+    0x27,0x00,0x00,0xd8,0x4f,0x00,0x00,0x00,0x00,0xc2,0x67,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x35,0xd8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xf2,
+    0x16,0x00,0x00,0xc6,0x3f,0x00,0x00,0x00,0x65,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x1f,0xc7,0xef,0xd1,0x29,0x2c,0xe4,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x0d,0xd1,0xfa,0x8f,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xf6,
+    0x0a,0x00,0x00,0x00,0x00,0x00,0xca,0x3b,0x00,0x00,0x23,0xec,0x3c,0x3d,0xea,0x21,
+    0x00,0x00,0x07,0x93,0x93,0x93,0xe0,0xb0,0x93,0x93,0x5a,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0xcd,
+    0x00,0x00,0x00,0xf0,0x3e,0x00,0x00,0x00,0x00,0xb0,0x7f,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x25,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x25,0xe4,
+    0x00,0x00,0x03,0xf4,0x0f,0x00,0x00,0x00,0x4d,0xec,0x20,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x06,0x00,0x00,0xba,0x63,0x07,0x82,0xc2,0x8d,0x0c,0x00,0x00,0x00,
+    0x24,0xda,0x7b,0x97,0xc2,0x0b,0x00,0x01,0xa2,0x03,0x00,0x00,0x00,0x00,0x2a,0xe1,
+    0x00,0x00,0x00,0x00,0x00,0x00,0xa3,0x69,0x00,0x00,0x0a,0x5b,0x00,0x00,0x5d,0x0a,
+    0x00,0x00,0x00,0x00,0x00,0x00,0xb6,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa4,0x74,
+    0x00,0x00,0x00,0xf6,0x3a,0x00,0x00,0x00,0x00,0xab,0x85,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x09,0xaa,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x67,0xbe,
+    0x1e,0x1e,0x40,0xe4,0x1e,0x1e,0x08,0x00,0x01,0x96,0xf2,0x91,0x2b,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x4c,0xce,0x02,0x8c,0xb1,0x37,0xa3,0xa2,0x00,0x00,0x00,
+    0xc6,0x75,0x00,0x01,0x9c,0xbe,0x0a,0x28,0xd1,0x00,0x00,0x00,0x00,0x00,0x57,0xbc,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x7d,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0xb6,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0xf1,0x1c,
+    0x00,0x00,0x00,0xde,0x49,0x00,0x00,0x00,0x00,0xbc,0x6d,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0xcb,0xea,0xe2,
+    0xcb,0xcb,0xe1,0xeb,0xcb,0xcb,0x37,0x00,0x00,0x00,0x2d,0x93,0xee,0xb4,0x1f,0x00,
+    0x00,0x00,0x00,0x00,0x05,0xd8,0x40,0x00,0xe2,0x2e,0x00,0x19,0xf5,0x02,0x00,0x13,
+    0xff,0x1d,0x00,0x00,0x02,0xa1,0xbb,0x94,0x7b,0x00,0x00,0x00,0x00,0x00,0x84,0x96,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x56,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0xb6,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0xc0,0x00,
+    0x00,0x00,0x00,0xc4,0x6e,0x00,0x00,0x00,0x00,0xe2,0x53,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb6,0x52,
+    0x00,0x00,0x8b,0x7d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xa7,0xd7,0x04,
+    0x00,0x00,0x00,0x00,0x70,0xad,0x00,0x00,0xf2,0x15,0x00,0x06,0xf7,0x0a,0x00,0x10,
+    0xff,0x23,0x00,0x00,0x00,0x03,0xb2,0xfb,0x13,0x00,0x00,0x00,0x00,0x00,0x7e,0x9b,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb3,0x67,0x00,
+    0x00,0x00,0x00,0x77,0xb5,0x00,0x00,0x00,0x2b,0xf5,0x0f,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x33,0x8c,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x20,
+    0x00,0x00,0xbd,0x4b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0xfc,0x2c,
+    0x00,0x00,0x00,0x13,0xe7,0x23,0x00,0x00,0xc1,0x5c,0x00,0x47,0xd7,0x00,0x00,0x00,
+    0xb5,0xaf,0x0d,0x00,0x0a,0x60,0xe1,0xbd,0xa5,0x01,0x00,0x00,0x00,0x00,0x51,0xc1,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0xf4,0x13,0x00,
+    0x00,0x00,0x00,0x19,0xf3,0x57,0x00,0x0b,0xc0,0x98,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7f,0xfe,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1b,0xec,0x00,
+    0x00,0x01,0xee,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0xef,0x0c,
+    0x00,0x00,0x00,0x94,0x8a,0x00,0x00,0x00,0x35,0xe8,0xc4,0xed,0x44,0x00,0x00,0x00,
+    0x15,0xa9,0xf1,0xdc,0xea,0xaf,0x1e,0x07,0xc7,0x73,0x00,0x00,0x00,0x00,0x24,0xe6,
+    0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0xb3,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x3c,0xea,0xdb,0xf2,0xae,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x02,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x85,0x9b,0x61,0x52,0x6c,0xd1,0x89,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x34,0x10,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x03,0x1b,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xf4,
+    0x0d,0x00,0x00,0x00,0x00,0x00,0xcf,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc1,0x5a,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x02,0x2c,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x69,0x8f,0xe2,0xa5,0x28,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xba,
+    0x5e,0x00,0x00,0x00,0x00,0x26,0xe9,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1d,0xf2,0x0b,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x52,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,
+    0xe1,0x0a,0x00,0x00,0x00,0xaf,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x76,0xa6,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x93,0x46,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xa1,0x7d,0x00,0x00,0x3e,0xd9,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x4d,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x1a,0xd2,0x03,0x00,0xa0,0x4f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2a,0xed,0x06,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x05,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x1a,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x28,0xb6,0x00,0x14,0x93,0xe1,0xe8,0x99,0x42,0x00,0x00,0x00,
+    0x2b,0xaa,0xea,0xf3,0xca,0x4e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0xbd,
+    0x30,0x00,0x00,0x00,0x63,0xbe,0xbe,0xbe,0xbe,0x94,0x00,0x00,0x00,0x00,0x00,0x0d,
+    0x5a,0x8c,0x92,0x00,0x00,0x9e,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0x3a,0x00,0x00,0x39,
+    0xbe,0xed,0xde,0x94,0x0f,0x00,0x00,0x00,0x47,0xc5,0xf0,0xce,0x62,0x00,0x00,0x00,
+    0x6a,0x88,0x00,0x00,0x00,0x6a,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x2a,0x29,0x00,0x02,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x18,0x00,0x00,0x4a,0x0a,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xd0,0xf3,0xe5,0xa3,0x17,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x36,0xe8,0xfb,0x00,0x98,0x8a,0x21,0x16,0x68,0xfb,0x1d,0x00,0x00,
+    0x3a,0x6a,0x22,0x11,0x62,0xf8,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0xd7,0xed,
+    0x41,0x00,0x00,0x00,0x8e,0x8e,0x38,0x38,0x38,0x2c,0x00,0x00,0x00,0x00,0x42,0xdd,
+    0xa9,0x5c,0x2b,0x00,0x00,0x39,0x45,0x45,0x45,0x45,0x5a,0xf1,0x24,0x00,0x25,0xef,
+    0x54,0x05,0x17,0xad,0xb3,0x00,0x00,0x3e,0xe9,0x46,0x08,0x39,0xe1,0x65,0x00,0x00,
+    0xaf,0xd8,0x00,0x00,0x00,0xaf,0xd8,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x50,0xbc,
+    0xe2,0x4f,0x00,0x0a,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0x7c,0x00,0x02,0xaa,0xe9,
+    0x8b,0x21,0x00,0x00,0x00,0x00,0x00,0x32,0x49,0x0e,0x16,0xae,0xb1,0x00,0x00,0x00,
+    0x00,0x0d,0xad,0xdf,0x61,0xfb,0x00,0x02,0x00,0x00,0x00,0x00,0xba,0x7a,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0xac,0x86,0x00,0x00,0x00,0x00,0x00,0x05,0xc6,0x50,0xd4,
+    0x41,0x00,0x00,0x00,0x9b,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x43,0xf1,0x36,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xae,0x71,0x00,0x00,0x7d,0xa3,
+    0x00,0x00,0x00,0x18,0xff,0x13,0x00,0xb6,0x78,0x00,0x00,0x00,0x4b,0xe0,0x04,0x00,
+    0x02,0x05,0x00,0x00,0x00,0x02,0x05,0x00,0x00,0x00,0x00,0x13,0x76,0xdf,0xbe,0x53,
+    0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1d,
+    0x84,0xe6,0xb1,0x45,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0xeb,0x00,0x00,0x00,
+    0x00,0x01,0x58,0x08,0x1e,0xfb,0x00,0x00,0x00,0x00,0x00,0x00,0x84,0xa8,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0xaa,0x70,0x00,0x00,0x00,0x00,0x00,0x87,0x8a,0x00,0xd4,
+    0x41,0x00,0x00,0x00,0xad,0x4e,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xd0,0x54,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0xd4,0x02,0x00,0x00,0x8b,0x93,
+    0x00,0x00,0x00,0x1e,0xff,0x18,0x00,0xe2,0x4c,0x00,0x00,0x00,0x06,0xfb,0x24,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x9d,0xe9,0x94,0x2a,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x06,0x5b,0xc5,0xd6,0x4e,0x00,0x00,0x00,0x00,0x00,0x75,0xbd,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xfb,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x69,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x3e,0xe4,0x1c,0x00,0x00,0x00,0x00,0x39,0xd0,0x07,0x00,0xd4,
+    0x41,0x00,0x00,0x00,0xc5,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0xeb,0x04,0x01,
+    0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xcc,0x58,0x00,0x00,0x00,0x45,0xe5,
+    0x1a,0x00,0x00,0x74,0xc5,0x00,0x00,0xd2,0x80,0x00,0x00,0x00,0x00,0xe9,0x41,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0xd8,0xcb,0x58,0x06,0x00,0x00,
+    0x00,0x00,0x00,0x08,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x5c,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x21,0x89,0xef,0x73,0x00,0x00,0x00,0x00,0x2b,0xe6,0x32,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xfb,0x00,0x00,0x00,0x00,0x00,0x70,0xd1,0x06,0x00,0x00,
+    0x00,0x00,0x82,0xd2,0xed,0x2e,0x00,0x00,0x00,0x00,0x03,0xcd,0x3d,0x00,0x00,0xd4,
+    0x41,0x00,0x00,0x00,0xc5,0xf6,0xe8,0xb5,0x3e,0x00,0x00,0x00,0x71,0xdc,0xc6,0xef,
+    0xf3,0xc1,0x30,0x00,0x00,0x00,0x00,0x00,0x48,0xd8,0x02,0x00,0x00,0x00,0x00,0x5c,
+    0xe9,0x8e,0x7d,0xd8,0x20,0x00,0x00,0x82,0xd4,0x1c,0x00,0x00,0x16,0xed,0x39,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x46,0xb3,0xe4,0x81,0x1b,
+    0x00,0x00,0x00,0x05,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x37,0x00,0x00,0x00,0x01,
+    0x47,0xb2,0xe5,0x81,0x1a,0x00,0x00,0x00,0x00,0x1d,0xdf,0x49,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xfb,0x00,0x00,0x00,0x00,0x67,0xe2,0x1f,0x00,0x00,0x00,
+    0x00,0x00,0x25,0x4b,0x95,0xea,0x3f,0x00,0x00,0x00,0x63,0xac,0x00,0x00,0x00,0xd4,
+    0x41,0x00,0x00,0x00,0x00,0x00,0x17,0x6c,0xee,0x5c,0x00,0x00,0x94,0xb6,0x29,0x02,
+    0x1d,0x8a,0xef,0x11,0x00,0x00,0x00,0x00,0xaf,0x78,0x00,0x00,0x00,0x00,0x03,0x9e,
+    0xc5,0x6f,0xc8,0xc2,0x19,0x00,0x00,0x0c,0xab,0xfd,0xc6,0xcd,0xdb,0xff,0x17,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0x8d,0xea,
+    0xab,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x71,0xda,
+    0xc7,0x5b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0xaa,0x76,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xfb,0x00,0x00,0x00,0x6f,0xe1,0x24,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x6a,0xe0,0x01,0x00,0x02,0xd9,0x45,0x16,0x16,0x16,0xd7,
+    0x51,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0xed,0x01,0x00,0xa1,0x81,0x00,0x00,
+    0x00,0x06,0xf1,0x65,0x00,0x00,0x00,0x0d,0xf6,0x20,0x00,0x00,0x00,0x00,0x76,0xc8,
+    0x07,0x00,0x00,0x63,0xe6,0x0a,0x00,0x00,0x00,0x16,0x3b,0x26,0x3e,0xf2,0x00,0x00,
+    0x56,0x70,0x00,0x00,0x00,0x4a,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,
+    0x66,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x35,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xea,0x11,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xfb,0x00,0x00,0x59,0xe6,0x23,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x18,0xff,0x1c,0x00,0x1f,0xcf,0xcf,0xcf,0xcf,0xcf,0xf7,
+    0xdc,0x94,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0xff,0x20,0x00,0x64,0x92,0x00,0x00,
+    0x00,0x00,0xb4,0x81,0x00,0x00,0x00,0x5a,0xc7,0x00,0x00,0x00,0x00,0x00,0xca,0x72,
+    0x00,0x00,0x00,0x00,0xdc,0x4d,0x00,0x00,0x00,0x00,0x00,0x00,0x8d,0x9b,0x00,0x00,
+    0xbb,0xe4,0x00,0x00,0x00,0x80,0xaa,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xfb,0x00,0x13,0xec,0x3a,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x4c,0xfc,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd4,
+    0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0xfe,0x0d,0x00,0x21,0xcc,0x00,0x00,
+    0x00,0x00,0xca,0x63,0x00,0x00,0x00,0x9b,0x8e,0x00,0x00,0x00,0x00,0x00,0xca,0x5e,
+    0x00,0x00,0x00,0x00,0xce,0x54,0x00,0x00,0x00,0x00,0x00,0x41,0xed,0x18,0x00,0x00,
+    0x09,0x11,0x00,0x00,0x00,0x9b,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xfb,0x00,0x6d,0xb6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x25,0x04,0x00,0x01,0x32,0xc1,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd4,
+    0x41,0x00,0x00,0x22,0x06,0x00,0x00,0x10,0xb0,0xac,0x00,0x00,0x00,0xdd,0x5b,0x00,
+    0x00,0x4b,0xec,0x10,0x00,0x00,0x00,0xc6,0x63,0x00,0x00,0x00,0x00,0x00,0x7a,0xcb,
+    0x11,0x00,0x00,0x52,0xeb,0x14,0x00,0x00,0x03,0x22,0x88,0xda,0x4b,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x01,0xe0,0x2e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x8e,0x2b,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xfb,0x00,0x9b,0xfb,0xf6,0xf6,0xf6,0xf6,0xf6,0x21,0x00,
+    0xa4,0xf0,0xcc,0xe7,0xfd,0x9d,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd4,
+    0x41,0x00,0x00,0x8f,0xf2,0xce,0xd2,0xf4,0xa2,0x13,0x00,0x00,0x00,0x33,0xe0,0xd8,
+    0xcd,0xe0,0x3a,0x00,0x00,0x00,0x01,0xf1,0x38,0x00,0x00,0x00,0x00,0x00,0x04,0x91,
+    0xea,0xbe,0xcf,0xdc,0x3f,0x00,0x00,0x52,0xe1,0xbf,0x89,0x10,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x0b,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0xfe,0x70,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x17,0x39,0x2e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x12,0x37,0x30,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x24,
+    0x28,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x0e,0x34,0x24,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0x01,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x0e,0x7d,0xb2,0xdc,0xe5,0xb8,0x84,0x14,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x30,0xbd,0x15,0x00,0x00,0x00,0x00,0x00,0x45,0xb2,0xce,0xd4,
+    0xc2,0x9a,0x42,0x00,0x00,0x00,0x00,0x00,0x12,0x90,0xce,0xf7,0xea,0xb6,0x4c,0x00,
+    0x45,0xb1,0xcb,0xd0,0xb0,0x8b,0x34,0x00,0x00,0x00,0x00,0x5a,0xbe,0xbe,0xbe,0xbe,
+    0xbe,0xbe,0x3a,0x00,0x5a,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0x2a,0x00,0x00,0x00,0x11,
+    0x8e,0xcb,0xf4,0xdf,0xbb,0x5f,0x00,0x5a,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0xb4,
+    0x27,0x00,0x5a,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x94,0x00,0x5a,0x81,0x00,
+    0x00,0x00,0x00,0x21,0xb7,0x2f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x54,0xe4,0x9c,0x4a,0x1d,0x13,0x45,0x8c,0xe7,0x5c,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xa6,0xec,0x7f,0x00,0x00,0x00,0x00,0x00,0x79,0xc0,0x2c,0x27,
+    0x39,0x74,0xeb,0x79,0x00,0x00,0x00,0x37,0xe5,0x9f,0x43,0x16,0x29,0x63,0x62,0x00,
+    0x79,0xc1,0x31,0x2d,0x4f,0x7b,0xe7,0xa6,0x0f,0x00,0x00,0x79,0xc2,0x41,0x41,0x41,
+    0x41,0x41,0x14,0x00,0x79,0xc2,0x41,0x41,0x41,0x41,0x41,0x0e,0x00,0x00,0x37,0xe4,
+    0x9e,0x3b,0x13,0x28,0x5b,0x83,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xc7,0x00,0x79,0xad,0x00,
+    0x00,0x00,0x1b,0xda,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x39,0xeb,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0xe5,0x44,0x00,0x00,
+    0x00,0x00,0x00,0x1f,0xed,0x45,0xea,0x09,0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,
+    0x00,0x00,0x42,0xf4,0x06,0x00,0x08,0xd9,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x10,0xb6,0xa5,0x00,0x00,0x79,0xad,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xda,0x73,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xc7,0x00,0x79,0xad,0x00,
+    0x00,0x1b,0xd9,0x6b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x07,0xd6,0x67,0x00,0x00,0x19,0x63,0x86,0x70,0x36,0x00,0x53,0xe2,0x0e,0x00,
+    0x00,0x00,0x00,0x89,0x93,0x00,0xcb,0x61,0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,
+    0x00,0x00,0x1b,0xfd,0x13,0x00,0x72,0xd4,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x19,0xf0,0x4d,0x00,0x79,0xad,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x72,0xd1,0x03,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xc7,0x00,0x79,0xad,0x00,
+    0x1d,0xd9,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4f,0xd4,0x02,0x00,0x3f,0xe7,0x94,0x64,0x8d,0xe1,0x00,0x00,0xc8,0x50,0x00,
+    0x00,0x00,0x08,0xea,0x29,0x00,0x60,0xc9,0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,
+    0x00,0x00,0x80,0xc2,0x00,0x00,0xac,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x8d,0x00,0x79,0xad,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x81,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xc7,0x00,0x79,0xad,0x22,
+    0xda,0x5f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x7b,0x99,0x00,0x05,0xdc,0x5a,0x00,0x00,0x34,0xe1,0x00,0x00,0x91,0x82,0x00,
+    0x00,0x00,0x5d,0xc5,0x00,0x00,0x0b,0xf1,0x32,0x00,0x00,0x00,0x79,0xdf,0x9c,0x9c,
+    0xa6,0xd5,0xcc,0x12,0x00,0x00,0xd7,0x5a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0xbb,0x00,0x79,0xe3,0xa9,0xa9,0xa9,
+    0xa9,0x75,0x00,0x00,0x79,0xdf,0x9c,0x9c,0x9c,0x9c,0x5c,0x00,0x00,0xd7,0x5c,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x79,0xe2,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xfa,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xc7,0x00,0x79,0xcf,0xe6,
+    0x5b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0xa7,0x70,0x00,0x2b,0xf3,0x01,0x00,0x00,0x34,0xe1,0x00,0x00,0x6c,0xab,0x00,
+    0x00,0x00,0xc1,0x64,0x00,0x00,0x00,0x99,0x97,0x00,0x00,0x00,0x79,0xcc,0x5f,0x5f,
+    0x66,0x80,0xd4,0xc1,0x0f,0x00,0xe2,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x6f,0xc6,0x00,0x79,0xc7,0x52,0x52,0x52,
+    0x52,0x39,0x00,0x00,0x79,0xcd,0x63,0x63,0x63,0x63,0x3b,0x00,0x00,0xe2,0x52,0x00,
+    0x00,0x00,0x00,0x00,0x16,0x8f,0x00,0x79,0xca,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0xf7,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xc7,0x00,0x79,0xc5,0xba,
+    0xd2,0x25,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0xb9,0x60,0x00,0x3d,0xe4,0x00,0x00,0x00,0x34,0xe1,0x00,0x00,0x79,0x98,0x00,
+    0x00,0x24,0xfb,0x41,0x34,0x34,0x34,0x68,0xf0,0x0a,0x00,0x00,0x79,0xad,0x00,0x00,
+    0x00,0x00,0x08,0xce,0x80,0x00,0xbb,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x95,0x98,0x00,0x79,0xad,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xbb,0x72,0x00,
+    0x00,0x00,0x00,0x00,0x27,0xff,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xc7,0x00,0x79,0xad,0x01,
+    0x74,0xea,0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8f,0x87,0x00,0x16,0xfd,0x15,0x00,0x00,0x34,0xe1,0x00,0x00,0xb4,0x6d,0x00,
+    0x00,0x85,0xe3,0xc7,0xc7,0xc7,0xc7,0xc7,0xee,0x5e,0x00,0x00,0x79,0xad,0x00,0x00,
+    0x00,0x00,0x00,0x89,0xb2,0x00,0x90,0xae,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x07,0xdb,0x66,0x00,0x79,0xad,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0xaf,0x00,
+    0x00,0x00,0x00,0x00,0x27,0xff,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x76,0xc0,0x00,0x79,0xad,0x00,
+    0x00,0x50,0xec,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x64,0xb2,0x00,0x00,0xa8,0xae,0x0e,0x00,0x3d,0xfb,0x16,0x4b,0xec,0x0f,0x00,
+    0x02,0xe2,0x46,0x00,0x00,0x00,0x00,0x00,0x7c,0xbf,0x00,0x00,0x79,0xad,0x00,0x00,
+    0x00,0x00,0x00,0xb4,0x90,0x00,0x21,0xf5,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x86,0xce,0x06,0x00,0x79,0xad,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0xf6,0x32,
+    0x00,0x00,0x00,0x00,0x27,0xff,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0xa5,0x00,0x79,0xad,0x00,
+    0x00,0x00,0x52,0xee,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x2a,0xf3,0x24,0x00,0x0f,0x96,0xe4,0xe3,0xc4,0xa4,0xf0,0xcd,0x33,0x00,0x00,
+    0x45,0xe5,0x03,0x00,0x00,0x00,0x00,0x00,0x21,0xfd,0x22,0x00,0x79,0xad,0x00,0x00,
+    0x00,0x21,0x8d,0xed,0x2a,0x00,0x00,0x74,0xec,0x50,0x04,0x00,0x00,0x11,0x33,0x00,
+    0x79,0xad,0x00,0x00,0x0d,0x37,0xb5,0xdf,0x27,0x00,0x00,0x79,0xad,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0xec,
+    0x53,0x05,0x00,0x00,0x28,0xff,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x4f,0x28,0x00,0x04,0x48,0xf5,0x51,0x00,0x79,0xad,0x00,
+    0x00,0x00,0x00,0x6e,0xe1,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x8a,0xbf,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xa4,0x8d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0x81,0x00,0x65,0xf3,0xeb,0xe4,
+    0xef,0xe5,0x97,0x29,0x00,0x00,0x00,0x00,0x4c,0xdd,0xf5,0xd1,0xe2,0xf7,0x95,0x00,
+    0x65,0xf3,0xef,0xeb,0xf0,0xcc,0x74,0x07,0x00,0x00,0x00,0x79,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xbe,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4b,
+    0xd9,0xf7,0xd1,0xd4,0xf2,0xd1,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x75,0xf0,0xd8,0xe9,0xfd,0x86,0x02,0x00,0x79,0xad,0x00,
+    0x00,0x00,0x00,0x00,0xad,0xa9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x08,0xcf,0xbd,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x11,0x15,
+    0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x3a,0x30,0x0a,0x00,0x00,
+    0x00,0x02,0x10,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x10,0x34,0x24,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x30,0x33,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x07,0x78,0xeb,0xba,0x91,0x72,0x7c,0x72,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x12,0x41,0x68,0x84,0x76,0x44,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x5a,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb7,0x37,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x6e,0x77,0x00,0x00,0x5a,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x7a,0x5d,0x00,0x00,0x00,0x13,0x93,0xcd,0xf3,0xd3,0x9e,0x1e,0x00,0x00,0x00,0x00,
+    0x44,0xaf,0xca,0xd3,0xbc,0x9b,0x39,0x00,0x00,0x00,0x00,0x00,0x13,0x93,0xcd,0xf3,
+    0xd3,0x9e,0x1e,0x00,0x00,0x00,0x00,0x44,0xaf,0xca,0xd3,0xbc,0x99,0x36,0x00,0x00,
+    0x00,0x00,0x00,0x09,0x63,0xab,0xee,0xed,0xb8,0x4b,0x00,0x00,0x84,0xbe,0xbe,0xbe,
+    0xbe,0xbe,0xbe,0xbe,0xbb,0x00,0x64,0x77,0x00,0x00,0x00,0x00,0x00,0x13,0xbe,0x0a,
+    0x00,0x85,0x6f,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xb1,0x34,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0xff,0xc4,0x01,0x00,0x00,
+    0x00,0x00,0x00,0x1a,0xf4,0xb2,0x00,0x00,0x79,0xff,0x78,0x00,0x00,0x00,0x00,0x00,
+    0xa4,0x7d,0x00,0x00,0x3c,0xe8,0x9c,0x3f,0x16,0x39,0x8c,0xee,0x4f,0x00,0x00,0x00,
+    0x79,0xc2,0x34,0x2b,0x3d,0x7d,0xed,0x83,0x00,0x00,0x00,0x3c,0xe8,0x9c,0x3f,0x16,
+    0x39,0x8c,0xee,0x4f,0x00,0x00,0x00,0x79,0xc2,0x35,0x2b,0x3c,0x7b,0xed,0x78,0x00,
+    0x00,0x00,0x00,0x6a,0xc2,0x30,0x08,0x1e,0x5e,0x58,0x00,0x00,0x2d,0x41,0x41,0x41,
+    0xf2,0x6b,0x41,0x41,0x40,0x00,0x86,0xa0,0x00,0x00,0x00,0x00,0x00,0x1a,0xff,0x0d,
+    0x00,0x63,0xe1,0x01,0x00,0x00,0x00,0x00,0x00,0x3d,0xed,0x07,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0xef,0xdd,0x4e,0x00,0x00,
+    0x00,0x00,0x00,0x98,0xcd,0xc8,0x00,0x00,0x79,0xc4,0xe6,0x4b,0x00,0x00,0x00,0x00,
+    0xa4,0x7d,0x00,0x09,0xdd,0x71,0x00,0x00,0x00,0x00,0x00,0x53,0xed,0x16,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x32,0xfe,0x27,0x00,0x09,0xdd,0x71,0x00,0x00,0x00,
+    0x00,0x00,0x53,0xed,0x16,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x3b,0xfd,0x1a,
+    0x00,0x00,0x02,0xd8,0x2b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x86,0xa0,0x00,0x00,0x00,0x00,0x00,0x1a,0xff,0x0d,
+    0x00,0x0f,0xf7,0x3a,0x00,0x00,0x00,0x00,0x00,0x95,0x98,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0xd8,0x61,0xcb,0x01,0x00,
+    0x00,0x00,0x1f,0xea,0x4a,0xdd,0x00,0x00,0x79,0xa9,0x3d,0xe9,0x1f,0x00,0x00,0x00,
+    0xa4,0x7d,0x00,0x76,0xd4,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xb9,0x94,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0xdc,0x5b,0x00,0x76,0xd4,0x03,0x00,0x00,0x00,
+    0x00,0x00,0x00,0xb9,0x94,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0xeb,0x49,
+    0x00,0x00,0x09,0xfc,0x2f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x86,0xa0,0x00,0x00,0x00,0x00,0x00,0x1a,0xff,0x0d,
+    0x00,0x00,0xac,0x93,0x00,0x00,0x00,0x00,0x04,0xe9,0x3c,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4e,0xc4,0x05,0xdf,0x4a,0x00,
+    0x00,0x00,0x97,0x84,0x27,0xf3,0x00,0x00,0x79,0xa9,0x00,0x79,0xc8,0x06,0x00,0x00,
+    0xa4,0x7d,0x00,0xad,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xcb,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x01,0xed,0x47,0x00,0xad,0x81,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x62,0xcb,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x09,0xf9,0x1f,
+    0x00,0x00,0x00,0xaf,0xc5,0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x86,0xa0,0x00,0x00,0x00,0x00,0x00,0x1a,0xff,0x0d,
+    0x00,0x00,0x4f,0xea,0x05,0x00,0x00,0x00,0x49,0xdc,0x01,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xb1,0x00,0x6a,0xc2,0x00,
+    0x00,0x18,0xed,0x15,0x14,0xff,0x09,0x00,0x79,0xa9,0x00,0x02,0xbc,0x88,0x00,0x00,
+    0xa4,0x7d,0x00,0xd8,0x5c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0xf4,0x02,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x75,0xeb,0x10,0x00,0xd8,0x5c,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x3e,0xf4,0x02,0x00,0x79,0xad,0x00,0x00,0x00,0x08,0x95,0xc4,0x00,
+    0x00,0x00,0x00,0x0e,0x9f,0xf5,0x9e,0x2f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x86,0xa0,0x00,0x00,0x00,0x00,0x00,0x1a,0xff,0x0d,
+    0x00,0x00,0x05,0xe8,0x4a,0x00,0x00,0x00,0xa4,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x75,0x9d,0x00,0x09,0xe8,0x3a,
+    0x00,0x88,0x92,0x00,0x03,0xfd,0x1b,0x00,0x79,0xa9,0x00,0x00,0x1b,0xea,0x3c,0x00,
+    0xa4,0x7d,0x00,0xe1,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0xfa,0x05,0x00,
+    0x79,0xd9,0x8a,0x90,0xa1,0xdb,0xda,0x38,0x00,0x00,0xe2,0x54,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x35,0xfc,0x06,0x00,0x79,0xe9,0xba,0xbd,0xc9,0xf2,0x90,0x0f,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x25,0x92,0xf2,0xa9,0x12,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x86,0xa0,0x00,0x00,0x00,0x00,0x00,0x1a,0xff,0x0d,
+    0x00,0x00,0x00,0x8c,0xa9,0x00,0x00,0x0f,0xf3,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x90,0x00,0x00,0x79,0xb0,
+    0x0d,0xea,0x1f,0x00,0x00,0xf2,0x29,0x00,0x79,0xa9,0x00,0x00,0x00,0x57,0xdc,0x0b,
+    0xa4,0x7d,0x00,0xb8,0x77,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0xd6,0x00,0x00,
+    0x79,0xd2,0x75,0x6f,0x5a,0x37,0x01,0x00,0x00,0x00,0xb9,0x77,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x59,0xdc,0x00,0x00,0x79,0xc2,0x41,0x40,0x4a,0xf0,0x40,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0xc5,0xb4,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x84,0xa4,0x00,0x00,0x00,0x00,0x00,0x1f,0xff,0x0b,
+    0x00,0x00,0x00,0x29,0xf7,0x12,0x00,0x66,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x91,0x85,0x00,0x00,0x10,0xf0,
+    0x96,0xa0,0x00,0x00,0x00,0xe7,0x38,0x00,0x79,0xa9,0x00,0x00,0x00,0x00,0xab,0x8a,
+    0xa4,0x7d,0x00,0x8b,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9a,0xa9,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8b,0xb8,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x9a,0xab,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x62,0xe3,0x12,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x34,0xfd,0x0c,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x6b,0xc2,0x00,0x00,0x00,0x00,0x00,0x3e,0xef,0x00,
+    0x00,0x00,0x00,0x00,0xbe,0x6e,0x00,0xca,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9f,0x7a,0x00,0x00,0x00,0x8e,
+    0xff,0x2d,0x00,0x00,0x00,0xdb,0x47,0x00,0x79,0xa9,0x00,0x00,0x00,0x00,0x16,0xe8,
+    0xcf,0x7d,0x00,0x1d,0xf3,0x43,0x00,0x00,0x00,0x00,0x00,0x29,0xf7,0x31,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1d,0xf4,0x43,0x00,0x00,0x00,
+    0x00,0x00,0x29,0xf9,0x32,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0xb1,0xa4,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3a,0xe9,0x09,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x3e,0xf3,0x16,0x00,0x00,0x00,0x00,0x86,0xc0,0x00,
+    0x00,0x00,0x00,0x00,0x55,0xd7,0x35,0xe4,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x6f,0x00,0x00,0x00,0x15,
+    0x46,0x00,0x00,0x00,0x00,0xd0,0x56,0x00,0x79,0xa9,0x00,0x00,0x00,0x00,0x00,0x61,
+    0xff,0x7d,0x00,0x00,0x6b,0xf1,0x5c,0x05,0x00,0x03,0x4c,0xe9,0x84,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6d,0xf1,0x5c,0x05,0x00,
+    0x03,0x4c,0xe9,0x84,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x1b,0xf0,0x44,
+    0x00,0x00,0x15,0x47,0x02,0x00,0x00,0x15,0xb7,0x7b,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x00,0xc4,0xb7,0x14,0x00,0x00,0x4f,0xf5,0x4a,0x00,
+    0x00,0x00,0x00,0x00,0x04,0xe1,0xd3,0x7b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xff,0xff,0xff,0xff,0xff,0xff,0x34,0x00,0xbb,0x64,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0xc4,0x65,0x00,0x79,0xa9,0x00,0x00,0x00,0x00,0x00,0x01,
+    0xc4,0x7d,0x00,0x00,0x00,0x41,0xd4,0xf7,0xd4,0xf4,0xde,0x52,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x43,0xd4,0xf7,0xd4,
+    0xf4,0xd5,0x5f,0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x75,0xcc,
+    0x01,0x00,0x33,0xda,0xee,0xc9,0xd9,0xdc,0x99,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x00,0x13,0xaf,0xf6,0xd5,0xe7,0xeb,0x58,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x75,0xf7,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x35,0x15,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x94,
+    0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1b,0x38,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x32,0x1f,0x01,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,
+    0xd6,0xa9,0x37,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x0a,0x75,0xce,0xf0,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x3e,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0xb1,
+    0x00,0x18,0xba,0x29,0x00,0x00,0x00,0x00,0x07,0xac,0x40,0x00,0x77,0x85,0x00,0x00,
+    0x00,0x00,0x00,0x07,0xb2,0x32,0x00,0x06,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0x7a,
+    0x00,0x15,0x45,0x45,0x45,0x08,0x00,0x18,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x3c,0x45,0x45,0x27,0x00,0x00,0x00,0x07,0xb1,0x65,0x00,0x00,0x00,0x00,0x12,0xcf,
+    0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0x51,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x1c,
+    0xc9,0xea,0xe5,0xad,0x20,0x00,0x00,0x02,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x1e,0xa5,0xde,0xea,0xc5,0x1a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x2c,0xfc,0x09,0x00,0x00,0x00,0x00,0x39,0x1d,0x00,0x00,0x00,0x00,0x62,0xc5,
+    0x00,0x00,0x81,0xc9,0x04,0x00,0x00,0x00,0x87,0xbb,0x01,0x00,0x28,0xf8,0x29,0x00,
+    0x00,0x00,0x00,0x6f,0xc4,0x01,0x00,0x02,0x41,0x41,0x41,0x41,0x41,0x49,0xe8,0x72,
+    0x00,0x4e,0xe4,0x93,0x93,0x11,0x00,0x20,0xee,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x7f,0x93,0xc8,0x8f,0x00,0x00,0x00,0x75,0xae,0xe3,0x14,0x00,0x00,0x00,0x03,0x23,
+    0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x0d,0x00,0xae,0x6d,0x00,0x00,0x00,0x00,0x09,
+    0x35,0x12,0x1b,0x8f,0xd4,0x03,0x00,0x89,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x1f,0xeb,0xb4,0x47,0x13,0x3e,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x05,0xf9,0x33,0x00,0x00,0x00,0x05,0xec,0x96,0x00,0x00,0x00,0x00,0x94,0x96,
+    0x00,0x00,0x05,0xcd,0x78,0x00,0x00,0x37,0xec,0x1d,0x00,0x00,0x00,0x95,0xa9,0x00,
+    0x00,0x00,0x0c,0xe7,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa4,0xaa,0x01,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0xc4,0x51,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x14,0xe3,0x19,0x7d,0x93,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0xe0,0x76,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x05,0xef,0x2b,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0xa3,0xb3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0xd2,0x62,0x00,0x00,0x00,0x47,0xee,0xe7,0x02,0x00,0x00,0x00,0xc7,0x66,
+    0x00,0x00,0x00,0x2c,0xf1,0x2b,0x08,0xd6,0x5d,0x00,0x00,0x00,0x00,0x15,0xee,0x35,
+    0x00,0x00,0x81,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x66,0xd9,0x0d,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x6b,0xab,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x92,0x7e,0x00,0x0a,0xdf,0x27,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0xc2,0x3d,0x00,0x00,0x00,
+    0x03,0x27,0x3b,0x24,0xd7,0x44,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0xe6,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x9f,0x96,0x00,0x00,0x00,0x9c,0x7a,0xe1,0x3e,0x00,0x00,0x04,0xf5,0x31,
+    0x00,0x00,0x00,0x00,0x75,0xcb,0x8e,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x69,0xcd,
+    0x03,0x23,0xe7,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2b,0xee,0x2f,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x16,0xf2,0x0e,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x26,0xe0,0x0b,0x00,0x00,0x61,0xb0,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x45,
+    0xde,0xd0,0xb7,0xce,0xfc,0x45,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x08,0xfe,0x2b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x6a,0xca,0x00,0x00,0x05,0xec,0x22,0x8d,0x92,0x00,0x00,0x2d,0xf5,0x05,
+    0x00,0x00,0x00,0x00,0x03,0xcb,0xf2,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xc7,
+    0x6e,0xb5,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xd0,0x6d,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0xb7,0x60,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0xaf,0x62,0x00,0x00,0x00,0x02,0xd0,0x3f,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xf0,
+    0x54,0x00,0x00,0x00,0xd4,0x45,0x00,0x8a,0xb6,0xa9,0xdd,0xd7,0x9c,0x15,0x00,0x00,
+    0x00,0xf0,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x34,0xf9,0x09,0x00,0x48,0xc6,0x00,0x33,0xe4,0x03,0x00,0x66,0xc3,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xeb,0xe9,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,
+    0xf4,0xc9,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0xb9,0x01,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x5e,0xba,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x31,0x03,0x00,0x00,0x00,0x00,0x26,0x0d,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0xfc,
+    0x04,0x00,0x00,0x00,0xd4,0x45,0x00,0x8a,0xdb,0x56,0x19,0x2e,0x95,0xe3,0x11,0x00,
+    0x00,0xbf,0x79,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x04,0xf0,0x41,0x00,0xa7,0x6a,0x00,0x00,0xd6,0x4a,0x00,0xa5,0x84,0x00,
+    0x00,0x00,0x00,0x02,0xbd,0x79,0x49,0xe9,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xc0,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0xec,0x1c,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0xf3,0x18,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xf1,
+    0x58,0x00,0x00,0x00,0xd4,0x45,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xb4,0x83,0x00,
+    0x00,0x42,0xef,0x4c,0x01,0x00,0x0b,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0xb2,0x7f,0x12,0xef,0x12,0x00,0x00,0x76,0xaf,0x00,0xe4,0x41,0x00,
+    0x00,0x00,0x00,0x6f,0xc7,0x03,0x00,0x9b,0xb0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xbe,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xcf,0x66,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xaa,0x6e,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4b,
+    0xe4,0xdf,0xce,0xdb,0xf0,0x39,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x5b,0xc7,0x00,
+    0x00,0x00,0x50,0xe1,0xf1,0xda,0xee,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x6d,0xc7,0x6c,0xa2,0x00,0x00,0x00,0x17,0xf6,0x3e,0xf4,0x08,0x00,
+    0x00,0x00,0x1c,0xed,0x29,0x00,0x00,0x0f,0xe4,0x52,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xbe,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0xc3,0x01,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0xc8,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x03,0x1f,0x2c,0x1a,0x01,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x44,0xe8,0x00,
+    0x00,0x00,0x00,0x00,0x15,0x23,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x1c,0xfb,0xd9,0x3a,0x00,0x00,0x00,0x00,0xaa,0xd7,0xad,0x00,0x00,
+    0x00,0x00,0xa8,0x82,0x00,0x00,0x00,0x00,0x53,0xdf,0x09,0x00,0x00,0x00,0x00,0x00,
+    0xbe,0x68,0x00,0x00,0x00,0x00,0x00,0x12,0xec,0x32,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xef,0x23,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x80,0xcd,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xc6,0xd0,0x00,0x00,0x00,0x00,0x00,0x3e,0xff,0x5c,0x00,0x00,
+    0x00,0x40,0xe4,0x0a,0x00,0x00,0x00,0x00,0x00,0xbd,0x80,0x00,0x00,0x00,0x00,0x00,
+    0xbe,0x68,0x00,0x00,0x00,0x00,0x00,0x59,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9e,0x7d,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xd3,0x96,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0xd6,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x26,0x8e,0xf0,0x19,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xe7,0x31,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6e,0xf4,0xdc,0xd5,0xfd,0xc8,0x2d,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x91,0x8b,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1d,0x2d,0x0f,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0xe3,0x02,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xec,0xb6,0xb6,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xdc,0x40,0x00,
+    0x9d,0xb6,0xda,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x0b,0x23,0x23,0x23,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x10,0x00,
+    0x1e,0x23,0x23,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0c,0x00,0x00,0x00,0x24,0xae,0xe4,
+    0xa9,0x40,0x01,0x00,0x00,0x00,0x00,0x00,0x14,0x11,0x00,0x00,0x00,0x00,0x17,0x98,
+    0xd1,0xe4,0xce,0xa5,0x20,0x00,0x02,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,
+    0x14,0x00,0x00,0x00,0x00,0x14,0x14,0x00,0x02,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x02,0x0e,0x00,0x00,0x48,0xb3,0xd3,0xe5,0xa4,0x3e,0x2f,0xa4,0xdd,0xdb,0xa5,
+    0x17,0x00,0x00,0x48,0xb1,0xd2,0xe6,0xcf,0x8e,0x09,0x00,0x00,0x00,0x00,0x1b,0xa3,
+    0xdf,0xd8,0x94,0x0e,0x00,0x00,0x49,0xb7,0xd7,0xe7,0xc5,0x80,0x08,0x00,0x00,0x00,
+    0x00,0x11,0x8f,0xcb,0xe7,0xd4,0xb1,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xab,0x6c,0x00,0x00,0x1f,0xed,0x72,0x18,
+    0x55,0xd2,0x8a,0x00,0x00,0x00,0x56,0xbc,0xe7,0xec,0x4e,0x00,0x00,0x1d,0xe9,0x93,
+    0x30,0x18,0x2f,0xe3,0x41,0x00,0x89,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb6,
+    0xb6,0x00,0x00,0x00,0x00,0xb6,0xb6,0x00,0x89,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8d,0x8a,0x00,0x00,0x8a,0xab,0x24,0x18,0x43,0xe0,0xe3,0x5f,0x20,0x29,0xa4,
+    0xc8,0x00,0x00,0x8a,0xac,0x25,0x17,0x35,0xbd,0xab,0x00,0x00,0x00,0x1b,0xea,0xb6,
+    0x3e,0x4d,0xc7,0xd6,0x09,0x00,0x8a,0xac,0x25,0x1c,0x6c,0xd3,0xcf,0x07,0x00,0x00,
+    0x15,0xe3,0xc8,0x60,0x19,0x29,0xc3,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0xa5,0x8c,0x00,0x00,
+    0x00,0x46,0xf7,0x0d,0x00,0x0a,0xf1,0x45,0x03,0x01,0x04,0x00,0x00,0xa4,0xa1,0x00,
+    0x00,0x00,0x00,0xd8,0x41,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,
+    0x33,0x00,0x00,0x00,0x00,0x33,0x33,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x68,0xbf,0x00,0x00,0x00,0x11,
+    0xfb,0x1f,0x00,0x8a,0x8f,0x00,0x00,0x00,0x1d,0xfa,0x18,0x00,0x00,0x9f,0xb8,0x00,
+    0x00,0x00,0x00,0xdb,0x78,0x00,0x8a,0x8f,0x00,0x00,0x00,0x03,0xe8,0x78,0x00,0x00,
+    0x9b,0xcd,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0xe3,0x4b,0x16,0x16,
+    0x16,0x1c,0xf5,0x2f,0x00,0x4d,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0xe9,0x3e,0x00,
+    0x00,0x00,0x00,0xd8,0x41,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x3d,0xe0,0x00,0x00,0x00,0x00,
+    0xe2,0x3a,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xe4,0x3a,0x00,0x00,0xe4,0x6e,0x00,
+    0x00,0x00,0x00,0x90,0xbf,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x98,0xc1,0x00,0x00,
+    0xe2,0x79,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x08,0xfe,0xdd,0xd8,0xd8,
+    0xd8,0xd8,0xd8,0x3a,0x00,0x87,0x92,0x00,0x00,0x00,0x00,0x00,0x07,0xfe,0x24,0x00,
+    0x00,0x00,0x00,0xd8,0x41,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x69,
+    0x6d,0x00,0x00,0x00,0x00,0x69,0x6d,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x31,0xe9,0x00,0x00,0x00,0x00,
+    0xd5,0x45,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xd2,0x49,0x00,0x08,0xfe,0x2e,0x00,
+    0x00,0x00,0x00,0x50,0xe3,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x4b,0xe7,0x00,0x08,
+    0xfe,0x2d,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x22,0xa8,0xdd,0xd8,0x9d,0xc7,0x6c,0x00,0x00,0xf3,0x4f,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x8a,0xe4,0xc2,0xc2,0xc2,0x10,0x00,0x00,0xe3,0x45,0x00,
+    0x00,0x00,0x00,0xd8,0x41,0x00,0x8a,0xcf,0xc2,0xe4,0xce,0x8e,0x0a,0x00,0x00,0x8a,
+    0x8f,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x8a,0x8f,0x00,0x00,0x0d,0xad,0x43,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x30,0xe9,0x00,0x00,0x00,0x00,
+    0xd4,0x45,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xcf,0x49,0x00,0x00,0xee,0x5b,0x00,
+    0x00,0x00,0x00,0x7e,0xca,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x50,0xd2,0x00,0x00,
+    0xf2,0x32,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x24,0xed,0x7f,0x28,0x1d,0x62,0xe8,0x6c,0x00,0x00,0xc3,0xa2,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x8a,0xa2,0x2b,0x2b,0x2b,0x04,0x00,0x00,0xa3,0xaf,0x00,
+    0x00,0x00,0x00,0xd9,0x41,0x00,0x8a,0xba,0x37,0x18,0x35,0xbd,0xae,0x00,0x00,0x8a,
+    0x8f,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x8a,0x8f,0x00,0x09,0xbd,0x7e,0x00,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x30,0xe9,0x00,0x00,0x00,0x00,
+    0xd4,0x45,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xcf,0x49,0x00,0x00,0xba,0xa5,0x00,
+    0x00,0x00,0x00,0xc8,0x94,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x93,0xa0,0x00,0x00,
+    0xc2,0x74,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0xa5,0x95,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x46,0xf1,0x75,0x1b,
+    0x00,0x03,0x18,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0xe1,0xb6,
+    0x62,0x6e,0xb6,0xff,0x41,0x00,0x8a,0x8f,0x00,0x00,0x00,0x1d,0xfb,0x18,0x00,0x8a,
+    0x8f,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x8a,0x8f,0x08,0xb8,0x85,0x00,0x00,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x30,0xe9,0x00,0x00,0x00,0x00,
+    0xd4,0x45,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xcf,0x49,0x00,0x00,0x36,0xf2,0x77,
+    0x0f,0x18,0x87,0xf1,0x1a,0x00,0x8a,0xbf,0x18,0x00,0x00,0x4f,0xf2,0x28,0x00,0x00,
+    0x44,0xeb,0x39,0x00,0x00,0x22,0xd4,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0xe8,0x3d,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x4d,0xdd,0xfc,
+    0xdb,0xf2,0x7a,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x6f,
+    0x9e,0x9c,0x55,0xde,0x3d,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xe4,0x3a,0x00,0x8a,
+    0x8f,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x8a,0x97,0xb6,0x88,0x00,0x00,0x00,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x30,0xe9,0x00,0x00,0x00,0x00,
+    0xd4,0x45,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xcf,0x49,0x00,0x00,0x00,0x48,0xe3,
+    0xf0,0xf7,0xd4,0x32,0x00,0x00,0x8a,0xd3,0xe7,0xd5,0xea,0xdd,0x40,0x00,0x00,0x00,
+    0x00,0x56,0xe8,0xe4,0xd9,0xdf,0xdc,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x08,0xff,0x25,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x10,
+    0x25,0x09,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x27,0xff,0x1c,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xd2,0x49,0x00,0x8a,
+    0x8f,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x8a,0xdf,0xf4,0x38,0x00,0x00,0x00,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x1e,0x17,0x00,0x00,0x00,0x00,0x8a,0x8f,0x02,0x20,0x19,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x1f,0x1b,0x01,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0xed,0x62,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x09,0x00,
+    0x00,0x1f,0x9e,0xcc,0x01,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xcf,0x49,0x00,0x8a,
+    0x8f,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x8a,0x8f,0x4f,0xed,0x48,0x00,0x00,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0xb8,0xb5,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0xf2,0xd8,
+    0xdc,0xd3,0x8e,0x22,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xcf,0x49,0x00,0x8a,
+    0x8f,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x8a,0x8f,0x00,0x3e,0xed,0x3b,0x00,0x00,
+    0x00,0x8e,0x8b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x31,0xf6,0x7f,0x1c,0x00,0x00,0xae,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x22,
+    0x18,0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xcf,0x49,0x00,0x8a,
+    0x8f,0x00,0x00,0x00,0x00,0x8a,0x8e,0x00,0x8a,0x8f,0x00,0x00,0x52,0xe7,0x1d,0x00,
+    0x00,0x7b,0xab,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x3f,0xd8,0xfc,0xd2,0xe0,0xf1,0x55,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xcf,0x49,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0xa6,0x69,0x00,0x8a,0x8f,0x00,0x00,0x00,0x92,0xbc,0x01,
+    0x00,0x1f,0xdf,0xa9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x13,0x2d,0x1a,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1c,0xe0,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x03,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x03,0xd1,0xe1,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x1e,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x3d,0xac,0xd3,0xe8,0xd1,0x0b,0x00,0x00,0x2a,0x91,0xdc,0xe5,0xbd,0x0a,0x00,
+    0x3e,0x3e,0x00,0x00,0x00,0x00,0x00,0x7d,0x59,0x00,0x00,0x00,0x00,0xb2,0x24,0x00,
+    0x6b,0x76,0x00,0x00,0x00,0x00,0x4f,0x86,0x00,0x62,0x7e,0x00,0x00,0x00,0x01,0xb6,
+    0x24,0x00,0x00,0x00,0x54,0x7c,0x00,0x17,0xbc,0x26,0x00,0x00,0x00,0x92,0x57,0x00,
+    0x6b,0x77,0x00,0x00,0x00,0x00,0x6a,0x6a,0x00,0x14,0xc2,0xc2,0xc2,0xc2,0xc2,0xaf,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x07,0x00,0x15,0x34,0x00,0x0d,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x15,0x1a,0x00,0x00,0x00,0x01,0x00,0x00,0x1c,0xb6,0xb6,0xb6,
+    0xb6,0xb6,0xb6,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8a,0xab,0x1f,0x13,0x2a,0x00,0x00,0x00,0xc2,0x66,0x0a,0x16,0x44,0x00,0x00,
+    0x9c,0x7d,0x00,0x00,0x00,0x00,0x00,0xa4,0x75,0x00,0x00,0x00,0x00,0xe9,0x30,0x00,
+    0x4d,0xd4,0x00,0x00,0x00,0x00,0xa3,0x6f,0x00,0x41,0xda,0x00,0x00,0x00,0x27,0xff,
+    0x5f,0x00,0x00,0x00,0xa5,0x63,0x00,0x00,0x7b,0xc6,0x03,0x00,0x5c,0xd0,0x06,0x00,
+    0x4d,0xd8,0x00,0x00,0x00,0x00,0xc1,0x51,0x00,0x04,0x2b,0x2b,0x2b,0x2d,0xcd,0x96,
+    0x00,0x00,0x00,0x00,0x11,0xba,0xd8,0x35,0x00,0x4e,0xbe,0x00,0xb0,0xdc,0x48,0x00,
+    0x00,0x00,0x00,0x71,0xdc,0xde,0xb6,0x21,0x00,0x60,0x8a,0x00,0x27,0xbc,0x23,0x23,
+    0x23,0x23,0x53,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x1c,0xfa,0x04,0x00,0x00,0x00,0x00,0x00,
+    0x9c,0x7d,0x00,0x00,0x00,0x00,0x00,0xa4,0x75,0x00,0x00,0x00,0x00,0xe9,0x30,0x00,
+    0x0b,0xf6,0x1c,0x00,0x00,0x02,0xe8,0x25,0x00,0x06,0xf2,0x1d,0x00,0x00,0x6a,0xe9,
+    0x9d,0x00,0x00,0x01,0xe5,0x1b,0x00,0x00,0x03,0xc6,0x76,0x1c,0xe7,0x2d,0x00,0x00,
+    0x0b,0xf5,0x26,0x00,0x00,0x07,0xf4,0x11,0x00,0x00,0x00,0x00,0x00,0x7e,0xc1,0x05,
+    0x00,0x00,0x00,0x00,0x78,0xaa,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x46,0xdb,0x00,
+    0x00,0x00,0x0a,0xdb,0x0c,0x02,0x69,0xe5,0xc0,0xdb,0x21,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x02,0xd4,0xa4,0x1b,0x00,0x00,0x00,0x00,
+    0x9c,0xe0,0xc2,0xc2,0xbf,0x00,0x00,0xa4,0x75,0x00,0x00,0x00,0x00,0xe9,0x30,0x00,
+    0x00,0xad,0x6b,0x00,0x00,0x3c,0xce,0x00,0x00,0x00,0xb1,0x67,0x00,0x00,0xb1,0x67,
+    0xe4,0x01,0x00,0x31,0xd1,0x00,0x00,0x00,0x00,0x25,0xec,0xc9,0x75,0x00,0x00,0x00,
+    0x00,0xa8,0x7b,0x00,0x00,0x3e,0xcc,0x00,0x00,0x00,0x00,0x00,0x41,0xe4,0x19,0x00,
+    0x00,0x00,0x00,0x00,0x9e,0x70,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x08,0xfe,0x06,
+    0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x2e,0x0a,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x99,0xf2,0xa7,0x26,0x00,0x00,
+    0x9c,0x93,0x2b,0x2b,0x2a,0x00,0x00,0xa4,0x75,0x00,0x00,0x00,0x00,0xe9,0x30,0x00,
+    0x00,0x56,0xc1,0x00,0x00,0x91,0x75,0x00,0x00,0x00,0x6a,0xb5,0x00,0x0a,0xe7,0x08,
+    0xd7,0x32,0x00,0x7d,0x88,0x00,0x00,0x00,0x00,0x00,0xb2,0xfc,0x24,0x00,0x00,0x00,
+    0x00,0x4d,0xd9,0x01,0x00,0x81,0x8a,0x00,0x00,0x00,0x00,0x13,0xe4,0x44,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xa4,0x69,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x01,0xff,0x0d,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x84,0xf1,0x2b,0x00,
+    0x9c,0x7d,0x00,0x00,0x00,0x00,0x00,0x9b,0x84,0x00,0x00,0x00,0x00,0xe9,0x30,0x00,
+    0x00,0x08,0xec,0x22,0x05,0xe4,0x19,0x00,0x00,0x00,0x17,0xf4,0x11,0x51,0xa7,0x00,
+    0x84,0x84,0x00,0xd1,0x31,0x00,0x00,0x00,0x00,0x50,0xd4,0x80,0xc8,0x04,0x00,0x00,
+    0x00,0x04,0xe1,0x40,0x00,0xc9,0x3c,0x00,0x00,0x00,0x00,0xab,0x8e,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xa4,0x68,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0xff,0x0d,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa6,0x7f,0x00,
+    0x9c,0x7d,0x00,0x00,0x00,0x00,0x00,0x7f,0xab,0x00,0x00,0x00,0x00,0xe9,0x30,0x00,
+    0x00,0x00,0x8f,0x86,0x52,0xad,0x00,0x00,0x00,0x00,0x00,0xad,0x66,0xa8,0x50,0x00,
+    0x2d,0xdc,0x2c,0xcd,0x00,0x00,0x00,0x00,0x16,0xe4,0x2f,0x02,0xc3,0x7d,0x00,0x00,
+    0x00,0x00,0x77,0xad,0x1a,0xdd,0x01,0x00,0x00,0x00,0x57,0xda,0x08,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xa4,0x64,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0xfc,0x0d,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x00,0x00,0x10,0xe4,0x39,0x00,
+    0x9c,0x7d,0x00,0x00,0x00,0x00,0x00,0x27,0xf7,0x3f,0x00,0x00,0x02,0xeb,0x30,0x00,
+    0x00,0x00,0x25,0xea,0xc8,0x42,0x00,0x00,0x00,0x00,0x00,0x49,0xd3,0xe2,0x06,0x00,
+    0x00,0xce,0xc6,0x6a,0x00,0x00,0x00,0x00,0x9f,0x81,0x00,0x00,0x24,0xef,0x27,0x00,
+    0x00,0x00,0x10,0xed,0x92,0x86,0x00,0x00,0x00,0x0c,0xe3,0x45,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xc0,0x49,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0xe3,0x26,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x2d,0xf2,0xd7,0xd5,0xdf,0x8c,0x00,0x00,
+    0x9b,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0xeb,0xe6,0xdc,0xf1,0xda,0x22,0x00,
+    0x00,0x00,0x00,0xae,0xcf,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xe1,0x8d,0x00,0x00,
+    0x00,0x68,0xf6,0x10,0x00,0x00,0x00,0x3b,0xdc,0x08,0x00,0x00,0x00,0x7e,0xb3,0x00,
+    0x00,0x00,0x00,0x7f,0xff,0x2c,0x00,0x00,0x00,0x58,0xfe,0xee,0xee,0xee,0xee,0xee,
+    0x0c,0x00,0x17,0x8c,0xd4,0x09,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0x76,0xc9,
+    0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x20,0x21,0x00,0x00,0x00,0x00,
+    0x8a,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x1d,0x08,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x53,0xc7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x26,0xc3,0xaf,0x02,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0x4e,0xe4,
+    0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x5c,0xd5,0x0b,0x00,0x0f,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x17,0xd9,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x02,0xd3,0x3d,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0xd7,0x3b,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x08,0xb5,0xef,0xd9,0xec,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xc2,0xc7,0xe5,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xa5,0x60,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0xf9,0x0e,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x14,0x24,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x14,0x25,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xa4,0x68,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0xff,0x0d,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xf3,0xd8,0xd8,
+    0xd8,0xd8,0xe1,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xa4,0x68,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0xff,0x0d,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xa1,0x6d,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x05,0xff,0x09,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x87,0x8f,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x2a,0xeb,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x24,0xe1,0xa3,0x26,0x00,0x4e,0xbe,0x00,0x80,0xd9,0x71,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x0c,0x3c,0x16,0x00,0x0b,0x1a,0x00,0x3e,0x20,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+];
+
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/src/debug_render.rs
@@ -0,0 +1,219 @@
+/* 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 debug_font_data;
+use device::{Device, GpuMarker, ProgramId, VAOId, TextureId, VertexFormat};
+use device::{TextureFilter, VertexUsageHint, TextureTarget};
+use euclid::{Matrix4D, Point2D, Size2D, Rect};
+use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, TextureSampler};
+use internal_types::{DebugFontVertex, DebugColorVertex, RenderTargetMode, PackedColor};
+use std::f32;
+use webrender_traits::{ColorF, ImageFormat, DeviceUintSize};
+
+pub struct DebugRenderer {
+    font_vertices: Vec<DebugFontVertex>,
+    font_indices: Vec<u32>,
+    font_program_id: ProgramId,
+    font_vao: VAOId,
+    font_texture_id: TextureId,
+
+    tri_vertices: Vec<DebugColorVertex>,
+    tri_indices: Vec<u32>,
+    tri_vao: VAOId,
+    line_vertices: Vec<DebugColorVertex>,
+    line_vao: VAOId,
+    color_program_id: ProgramId,
+}
+
+impl DebugRenderer {
+    pub fn new(device: &mut Device) -> DebugRenderer {
+        let font_program_id = device.create_program("debug_font", "shared_other");
+        let color_program_id = device.create_program("debug_color", "shared_other");
+
+        let font_vao = device.create_vao(VertexFormat::DebugFont, 32);
+        let line_vao = device.create_vao(VertexFormat::DebugColor, 32);
+        let tri_vao = device.create_vao(VertexFormat::DebugColor, 32);
+
+        let font_texture_id = device.create_texture_ids(1, TextureTarget::Default)[0];
+        device.init_texture(font_texture_id,
+                            debug_font_data::BMP_WIDTH,
+                            debug_font_data::BMP_HEIGHT,
+                            ImageFormat::A8,
+                            TextureFilter::Linear,
+                            RenderTargetMode::None,
+                            Some(&debug_font_data::FONT_BITMAP));
+
+        DebugRenderer {
+            font_vertices: Vec::new(),
+            font_indices: Vec::new(),
+            line_vertices: Vec::new(),
+            tri_vao: tri_vao,
+            tri_vertices: Vec::new(),
+            tri_indices: Vec::new(),
+            font_program_id: font_program_id,
+            color_program_id: color_program_id,
+            font_vao: font_vao,
+            line_vao: line_vao,
+            font_texture_id: font_texture_id,
+        }
+    }
+
+    pub fn line_height(&self) -> f32 {
+        debug_font_data::FONT_SIZE as f32 * 1.1
+    }
+
+    pub fn add_text(&mut self,
+                    x: f32,
+                    y: f32,
+                    text: &str,
+                    color: &ColorF) -> Rect<f32> {
+        let mut x_start = x;
+        let ipw = 1.0 / debug_font_data::BMP_WIDTH as f32;
+        let iph = 1.0 / debug_font_data::BMP_HEIGHT as f32;
+        let color = PackedColor::from_color(color);
+
+        let mut min_x = f32::MAX;
+        let mut max_x = -f32::MAX;
+        let mut min_y = f32::MAX;
+        let mut max_y = -f32::MAX;
+
+        for c in text.chars() {
+            let c = c as usize - debug_font_data::FIRST_GLYPH_INDEX as usize;
+            if c < debug_font_data::GLYPHS.len() {
+                let glyph = &debug_font_data::GLYPHS[c];
+
+                let x0 = (x_start + glyph.xo + 0.5).floor();
+                let y0 = (y + glyph.yo + 0.5).floor();
+
+                let x1 = x0 + glyph.x1 as f32 - glyph.x0 as f32;
+                let y1 = y0 + glyph.y1 as f32 - glyph.y0 as f32;
+
+                let s0 = glyph.x0 as f32 * ipw;
+                let t0 = glyph.y0 as f32 * iph;
+                let s1 = glyph.x1 as f32 * ipw;
+                let t1 = glyph.y1 as f32 * iph;
+
+                x_start += glyph.xa;
+
+                let vertex_count = self.font_vertices.len() as u32;
+
+                self.font_vertices.push(DebugFontVertex::new(x0, y0, s0, t0, color));
+                self.font_vertices.push(DebugFontVertex::new(x1, y0, s1, t0, color));
+                self.font_vertices.push(DebugFontVertex::new(x0, y1, s0, t1, color));
+                self.font_vertices.push(DebugFontVertex::new(x1, y1, s1, t1, color));
+
+                self.font_indices.push(vertex_count + 0);
+                self.font_indices.push(vertex_count + 1);
+                self.font_indices.push(vertex_count + 2);
+                self.font_indices.push(vertex_count + 2);
+                self.font_indices.push(vertex_count + 1);
+                self.font_indices.push(vertex_count + 3);
+
+                min_x = min_x.min(x0);
+                max_x = max_x.max(x1);
+                min_y = min_y.min(y0);
+                max_y = max_y.max(y1);
+            }
+        }
+
+        Rect::new(Point2D::new(min_x, min_y), Size2D::new(max_x-min_x, max_y-min_y))
+    }
+
+    pub fn add_quad(&mut self,
+                    x0: f32,
+                    y0: f32,
+                    x1: f32,
+                    y1: f32,
+                    color_top: &ColorF,
+                    color_bottom: &ColorF) {
+        let color_top = PackedColor::from_color(color_top);
+        let color_bottom = PackedColor::from_color(color_bottom);
+        let vertex_count = self.tri_vertices.len() as u32;
+
+        self.tri_vertices.push(DebugColorVertex::new(x0, y0, color_top));
+        self.tri_vertices.push(DebugColorVertex::new(x1, y0, color_top));
+        self.tri_vertices.push(DebugColorVertex::new(x0, y1, color_bottom));
+        self.tri_vertices.push(DebugColorVertex::new(x1, y1, color_bottom));
+
+        self.tri_indices.push(vertex_count + 0);
+        self.tri_indices.push(vertex_count + 1);
+        self.tri_indices.push(vertex_count + 2);
+        self.tri_indices.push(vertex_count + 2);
+        self.tri_indices.push(vertex_count + 1);
+        self.tri_indices.push(vertex_count + 3);
+    }
+
+    #[allow(dead_code)]
+    pub fn add_line(&mut self,
+                    x0: i32,
+                    y0: i32,
+                    color0: &ColorF,
+                    x1: i32,
+                    y1: i32,
+                    color1: &ColorF) {
+        let color0 = PackedColor::from_color(color0);
+        let color1 = PackedColor::from_color(color1);
+        self.line_vertices.push(DebugColorVertex::new(x0 as f32, y0 as f32, color0));
+        self.line_vertices.push(DebugColorVertex::new(x1 as f32, y1 as f32, color1));
+    }
+
+    pub fn render(&mut self,
+                  device: &mut Device,
+                  viewport_size: &DeviceUintSize) {
+        let _gm = GpuMarker::new("debug");
+        device.disable_depth();
+        device.set_blend(true);
+        device.set_blend_mode_alpha();
+
+        let projection = Matrix4D::ortho(0.0,
+                                         viewport_size.width as f32,
+                                         viewport_size.height as f32,
+                                         0.0,
+                                         ORTHO_NEAR_PLANE,
+                                         ORTHO_FAR_PLANE);
+
+        // Triangles
+        if !self.tri_vertices.is_empty() {
+            device.bind_program(self.color_program_id, &projection);
+            device.bind_vao(self.tri_vao);
+            device.update_vao_indices(self.tri_vao,
+                                      &self.tri_indices,
+                                      VertexUsageHint::Dynamic);
+            device.update_vao_main_vertices(self.tri_vao,
+                                            &self.tri_vertices,
+                                            VertexUsageHint::Dynamic);
+            device.draw_triangles_u32(0, self.tri_indices.len() as i32);
+        }
+
+        // Lines
+        if !self.line_vertices.is_empty() {
+            device.bind_program(self.color_program_id, &projection);
+            device.bind_vao(self.line_vao);
+            device.update_vao_main_vertices(self.line_vao,
+                                            &self.line_vertices,
+                                            VertexUsageHint::Dynamic);
+            device.draw_nonindexed_lines(0, self.line_vertices.len() as i32);
+        }
+
+        // Glyph
+        if !self.font_indices.is_empty() {
+            device.bind_program(self.font_program_id, &projection);
+            device.bind_texture(TextureSampler::Color0, self.font_texture_id);
+            device.bind_vao(self.font_vao);
+            device.update_vao_indices(self.font_vao,
+                                      &self.font_indices,
+                                      VertexUsageHint::Dynamic);
+            device.update_vao_main_vertices(self.font_vao,
+                                            &self.font_vertices,
+                                            VertexUsageHint::Dynamic);
+            device.draw_triangles_u32(0, self.font_indices.len() as i32);
+        }
+
+        self.font_indices.clear();
+        self.font_vertices.clear();
+        self.line_vertices.clear();
+        self.tri_vertices.clear();
+        self.tri_indices.clear();
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/src/device.rs
@@ -0,0 +1,1965 @@
+/* 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::Matrix4D;
+use fnv::FnvHasher;
+use gleam::gl;
+use internal_types::{PackedVertex, RenderTargetMode, TextureSampler, DEFAULT_TEXTURE};
+use internal_types::{BlurAttribute, ClearAttribute, ClipAttribute, VertexAttribute};
+use internal_types::{DebugFontVertex, DebugColorVertex};
+//use notify::{self, Watcher};
+use super::shader_source;
+use std::collections::HashMap;
+use std::fs::File;
+use std::hash::BuildHasherDefault;
+use std::io::Read;
+use std::mem;
+use std::path::PathBuf;
+//use std::sync::mpsc::{channel, Sender};
+//use std::thread;
+use webrender_traits::{ColorF, ImageFormat};
+use webrender_traits::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
+
+#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
+const GL_FORMAT_A: gl::GLuint = gl::RED;
+
+#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+const GL_FORMAT_A: gl::GLuint = gl::ALPHA;
+
+#[cfg(any(target_os = "windows", all(unix, not(target_os = "android"))))]
+const GL_FORMAT_BGRA: gl::GLuint = gl::BGRA;
+
+#[cfg(target_os = "android")]
+const GL_FORMAT_BGRA: gl::GLuint = gl::BGRA_EXT;
+
+#[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";
+
+pub type ViewportDimensions = [u32; 2];
+
+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,
+    Array,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum TextureFilter {
+    Nearest,
+    Linear,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum VertexFormat {
+    Triangles,
+    Rectangles,
+    DebugFont,
+    DebugColor,
+    Clear,
+    Blur,
+    Clip,
+}
+
+enum FBOTarget {
+    Read,
+    Draw,
+}
+
+fn get_optional_shader_source(shader_name: &str, base_path: &Option<PathBuf>) -> Option<String> {
+    if let Some(ref base) = *base_path {
+        let shader_path = base.join(&format!("{}.glsl", shader_name));
+        if shader_path.exists() {
+            let mut source = String::new();
+            File::open(&shader_path).unwrap().read_to_string(&mut source).unwrap();
+            return Some(source);
+        }
+    }
+
+    shader_source::SHADERS.get(shader_name).and_then(|s| Some((*s).to_owned()))
+}
+
+fn get_shader_source(shader_name: &str, base_path: &Option<PathBuf>) -> String {
+    get_optional_shader_source(shader_name, base_path)
+        .expect(&format!("Couldn't get required shader: {}", shader_name))
+}
+
+pub trait FileWatcherHandler : Send {
+    fn file_changed(&self, path: PathBuf);
+}
+
+impl VertexFormat {
+    fn bind(&self, main: VBOId, instance: VBOId, offset: gl::GLuint, instance_stride: gl::GLint) {
+        main.bind();
+
+        match *self {
+            VertexFormat::DebugFont => {
+                gl::enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint);
+                gl::enable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint);
+                gl::enable_vertex_attrib_array(VertexAttribute::ColorTexCoord as gl::GLuint);
+
+                gl::vertex_attrib_divisor(VertexAttribute::Position as gl::GLuint, 0);
+                gl::vertex_attrib_divisor(VertexAttribute::Color as gl::GLuint, 0);
+                gl::vertex_attrib_divisor(VertexAttribute::ColorTexCoord as gl::GLuint, 0);
+
+                let vertex_stride = mem::size_of::<DebugFontVertex>() as gl::GLuint;
+
+                gl::vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint,
+                                          2,
+                                          gl::FLOAT,
+                                          false,
+                                          vertex_stride as gl::GLint,
+                                          0 + vertex_stride * offset);
+                gl::vertex_attrib_pointer(VertexAttribute::Color as gl::GLuint,
+                                          4,
+                                          gl::UNSIGNED_BYTE,
+                                          true,
+                                          vertex_stride as gl::GLint,
+                                          8 + vertex_stride * offset);
+                gl::vertex_attrib_pointer(VertexAttribute::ColorTexCoord as gl::GLuint,
+                                          2,
+                                          gl::FLOAT,
+                                          false,
+                                          vertex_stride as gl::GLint,
+                                          12 + vertex_stride * offset);
+            }
+            VertexFormat::DebugColor => {
+                gl::enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint);
+                gl::enable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint);
+
+                gl::vertex_attrib_divisor(VertexAttribute::Position as gl::GLuint, 0);
+                gl::vertex_attrib_divisor(VertexAttribute::Color as gl::GLuint, 0);
+
+                let vertex_stride = mem::size_of::<DebugColorVertex>() as gl::GLuint;
+
+                gl::vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint,
+                                          2,
+                                          gl::FLOAT,
+                                          false,
+                                          vertex_stride as gl::GLint,
+                                          0 + vertex_stride * offset);
+                gl::vertex_attrib_pointer(VertexAttribute::Color as gl::GLuint,
+                                          4,
+                                          gl::UNSIGNED_BYTE,
+                                          true,
+                                          vertex_stride as gl::GLint,
+                                          8 + vertex_stride * offset);
+            }
+            VertexFormat::Rectangles |
+            VertexFormat::Triangles => {
+                let vertex_stride = mem::size_of::<PackedVertex>() as gl::GLuint;
+                gl::enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint);
+                gl::vertex_attrib_divisor(VertexAttribute::Position as gl::GLuint, 0);
+
+                gl::vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint,
+                                          2,
+                                          gl::FLOAT,
+                                          false,
+                                          vertex_stride as gl::GLint,
+                                          0);
+
+                instance.bind();
+                let mut offset = 0;
+
+                for &attrib in [VertexAttribute::GlobalPrimId,
+                                VertexAttribute::PrimitiveAddress,
+                                VertexAttribute::TaskIndex,
+                                VertexAttribute::ClipTaskIndex,
+                                VertexAttribute::LayerIndex,
+                                VertexAttribute::ElementIndex,
+                                VertexAttribute::ZIndex,
+                               ].into_iter() {
+                    gl::enable_vertex_attrib_array(attrib as gl::GLuint);
+                    gl::vertex_attrib_divisor(attrib as gl::GLuint, 1);
+                    gl::vertex_attrib_i_pointer(attrib as gl::GLuint,
+                                                1,
+                                                gl::INT,
+                                                instance_stride,
+                                                offset);
+                    offset += 4;
+                }
+
+                gl::enable_vertex_attrib_array(VertexAttribute::UserData as gl::GLuint);
+                gl::vertex_attrib_divisor(VertexAttribute::UserData as gl::GLuint, 1);
+                gl::vertex_attrib_i_pointer(VertexAttribute::UserData as gl::GLuint,
+                                            2,
+                                            gl::INT,
+                                            instance_stride,
+                                            offset);
+            }
+            VertexFormat::Clear => {
+                let vertex_stride = mem::size_of::<PackedVertex>() as gl::GLuint;
+                gl::enable_vertex_attrib_array(ClearAttribute::Position as gl::GLuint);
+                gl::vertex_attrib_divisor(ClearAttribute::Position as gl::GLuint, 0);
+
+                gl::vertex_attrib_pointer(ClearAttribute::Position as gl::GLuint,
+                                          2,
+                                          gl::FLOAT,
+                                          false,
+                                          vertex_stride as gl::GLint,
+                                          0);
+
+                instance.bind();
+
+                gl::enable_vertex_attrib_array(ClearAttribute::Rectangle as gl::GLuint);
+                gl::vertex_attrib_divisor(ClearAttribute::Rectangle as gl::GLuint, 1);
+                gl::vertex_attrib_i_pointer(ClearAttribute::Rectangle as gl::GLuint,
+                                            4,
+                                            gl::INT,
+                                            instance_stride,
+                                            0);
+            }
+            VertexFormat::Blur => {
+                let vertex_stride = mem::size_of::<PackedVertex>() as gl::GLuint;
+                gl::enable_vertex_attrib_array(BlurAttribute::Position as gl::GLuint);
+                gl::vertex_attrib_divisor(BlurAttribute::Position as gl::GLuint, 0);
+
+                gl::vertex_attrib_pointer(BlurAttribute::Position as gl::GLuint,
+                                          2,
+                                          gl::FLOAT,
+                                          false,
+                                          vertex_stride as gl::GLint,
+                                          0);
+
+                instance.bind();
+
+                for (i, &attrib) in [BlurAttribute::RenderTaskIndex,
+                                     BlurAttribute::SourceTaskIndex,
+                                     BlurAttribute::Direction,
+                                    ].into_iter().enumerate() {
+                    gl::enable_vertex_attrib_array(attrib as gl::GLuint);
+                    gl::vertex_attrib_divisor(attrib as gl::GLuint, 1);
+                    gl::vertex_attrib_i_pointer(attrib as gl::GLuint,
+                                                1,
+                                                gl::INT,
+                                                instance_stride,
+                                                (i * 4) as gl::GLuint);
+                }
+            }
+            VertexFormat::Clip => {
+                let vertex_stride = mem::size_of::<PackedVertex>() as gl::GLuint;
+                gl::enable_vertex_attrib_array(ClipAttribute::Position as gl::GLuint);
+                gl::vertex_attrib_divisor(ClipAttribute::Position as gl::GLuint, 0);
+
+                gl::vertex_attrib_pointer(ClipAttribute::Position as gl::GLuint,
+                                          2,
+                                          gl::FLOAT,
+                                          false,
+                                          vertex_stride as gl::GLint,
+                                          0);
+
+                instance.bind();
+
+                for (i, &attrib) in [ClipAttribute::RenderTaskIndex,
+                                     ClipAttribute::LayerIndex,
+                                     ClipAttribute::DataIndex,
+                                     ClipAttribute::SegmentIndex,
+                                    ].into_iter().enumerate() {
+                    gl::enable_vertex_attrib_array(attrib as gl::GLuint);
+                    gl::vertex_attrib_divisor(attrib as gl::GLuint, 1);
+                    gl::vertex_attrib_i_pointer(attrib as gl::GLuint,
+                                                1,
+                                                gl::INT,
+                                                instance_stride,
+                                                (i * 4) as gl::GLuint);
+                }
+            }
+        }
+    }
+}
+
+impl TextureId {
+    pub fn bind(&self) {
+        gl::bind_texture(self.target, self.name);
+    }
+
+    pub fn new(name: gl::GLuint) -> TextureId {
+        TextureId {
+            name: name,
+            target: gl::TEXTURE_2D,
+        }
+    }
+
+    pub fn invalid() -> TextureId {
+        TextureId {
+            name: 0,
+            target: gl::TEXTURE_2D,
+        }
+    }
+
+    pub fn is_valid(&self) -> bool { *self != TextureId::invalid() }
+}
+
+impl ProgramId {
+    fn bind(&self) {
+        gl::use_program(self.0);
+    }
+}
+
+impl VBOId {
+    fn bind(&self) {
+        gl::bind_buffer(gl::ARRAY_BUFFER, self.0);
+    }
+}
+
+impl IBOId {
+    fn bind(&self) {
+        gl::bind_buffer(gl::ELEMENT_ARRAY_BUFFER, self.0);
+    }
+}
+
+impl UBOId {
+    fn _bind(&self) {
+        gl::bind_buffer(gl::UNIFORM_BUFFER, self.0);
+    }
+}
+
+impl FBOId {
+    fn bind(&self, target: FBOTarget) {
+        let target = match target {
+            FBOTarget::Read => gl::READ_FRAMEBUFFER,
+            FBOTarget::Draw => gl::DRAW_FRAMEBUFFER,
+        };
+        gl::bind_framebuffer(target, self.0);
+    }
+}
+
+struct Texture {
+    id: gl::GLuint,
+    format: ImageFormat,
+    width: u32,
+    height: u32,
+    filter: TextureFilter,
+    mode: RenderTargetMode,
+    fbo_ids: Vec<FBOId>,
+}
+
+impl Drop for Texture {
+    fn drop(&mut self) {
+        if !self.fbo_ids.is_empty() {
+            let fbo_ids: Vec<_> = self.fbo_ids.iter().map(|&FBOId(fbo_id)| fbo_id).collect();
+            gl::delete_framebuffers(&fbo_ids[..]);
+        }
+        gl::delete_textures(&[self.id]);
+    }
+}
+
+struct Program {
+    id: gl::GLuint,
+    u_transform: gl::GLint,
+    u_device_pixel_ratio: gl::GLint,
+    name: String,
+    vs_source: String,
+    fs_source: String,
+    prefix: Option<String>,
+    vs_id: Option<gl::GLuint>,
+    fs_id: Option<gl::GLuint>,
+}
+
+impl Program {
+    fn attach_and_bind_shaders(&mut self,
+                               vs_id: gl::GLuint,
+                               fs_id: gl::GLuint,
+                               panic_on_fail: bool) -> bool {
+        gl::attach_shader(self.id, vs_id);
+        gl::attach_shader(self.id, fs_id);
+
+        gl::bind_attrib_location(self.id, VertexAttribute::Position as gl::GLuint, "aPosition");
+        gl::bind_attrib_location(self.id, VertexAttribute::Color as gl::GLuint, "aColor");
+        gl::bind_attrib_location(self.id, VertexAttribute::ColorTexCoord as gl::GLuint, "aColorTexCoord");
+
+        gl::bind_attrib_location(self.id, VertexAttribute::GlobalPrimId as gl::GLuint, "aGlobalPrimId");
+        gl::bind_attrib_location(self.id, VertexAttribute::PrimitiveAddress as gl::GLuint, "aPrimitiveAddress");
+        gl::bind_attrib_location(self.id, VertexAttribute::TaskIndex as gl::GLuint, "aTaskIndex");
+        gl::bind_attrib_location(self.id, VertexAttribute::ClipTaskIndex as gl::GLuint, "aClipTaskIndex");
+        gl::bind_attrib_location(self.id, VertexAttribute::LayerIndex as gl::GLuint, "aLayerIndex");
+        gl::bind_attrib_location(self.id, VertexAttribute::ElementIndex as gl::GLuint, "aElementIndex");
+        gl::bind_attrib_location(self.id, VertexAttribute::UserData as gl::GLuint, "aUserData");
+        gl::bind_attrib_location(self.id, VertexAttribute::ZIndex as gl::GLuint, "aZIndex");
+
+        gl::bind_attrib_location(self.id, ClearAttribute::Rectangle as gl::GLuint, "aClearRectangle");
+
+        gl::bind_attrib_location(self.id, BlurAttribute::RenderTaskIndex as gl::GLuint, "aBlurRenderTaskIndex");
+        gl::bind_attrib_location(self.id, BlurAttribute::SourceTaskIndex as gl::GLuint, "aBlurSourceTaskIndex");
+        gl::bind_attrib_location(self.id, BlurAttribute::Direction as gl::GLuint, "aBlurDirection");
+
+        gl::bind_attrib_location(self.id, ClipAttribute::RenderTaskIndex as gl::GLuint, "aClipRenderTaskIndex");
+        gl::bind_attrib_location(self.id, ClipAttribute::LayerIndex as gl::GLuint, "aClipLayerIndex");
+        gl::bind_attrib_location(self.id, ClipAttribute::DataIndex as gl::GLuint, "aClipDataIndex");
+        gl::bind_attrib_location(self.id, ClipAttribute::SegmentIndex as gl::GLuint, "aClipSegmentIndex");
+
+        gl::link_program(self.id);
+        if gl::get_program_iv(self.id, gl::LINK_STATUS) == (0 as gl::GLint) {
+            println!("Failed to link shader program: {}", gl::get_program_info_log(self.id));
+            gl::detach_shader(self.id, vs_id);
+            gl::detach_shader(self.id, fs_id);
+            if panic_on_fail {
+                panic!("-- Program link failed - exiting --");
+            }
+            false
+        } else {
+            //println!("{}", gl::get_program_info_log(self.id));
+            true
+        }
+    }
+}
+
+impl Drop for Program {
+    fn drop(&mut self) {
+        gl::delete_program(self.id);
+    }
+}
+
+struct VAO {
+    id: gl::GLuint,
+    ibo_id: IBOId,
+    main_vbo_id: VBOId,
+    instance_vbo_id: VBOId,
+    instance_stride: gl::GLint,
+    owns_indices: bool,
+    owns_vertices: bool,
+    owns_instances: bool,
+}
+
+impl Drop for VAO {
+    fn drop(&mut self) {
+        gl::delete_vertex_arrays(&[self.id]);
+
+        if self.owns_indices {
+            // todo(gw): maybe make these their own type with hashmap?
+            gl::delete_buffers(&[self.ibo_id.0]);
+        }
+        if self.owns_vertices {
+            gl::delete_buffers(&[self.main_vbo_id.0]);
+        }
+        if self.owns_instances {
+            gl::delete_buffers(&[self.instance_vbo_id.0])
+        }
+    }
+}
+
+#[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Copy, Clone)]
+pub struct TextureId {
+    name: gl::GLuint,
+    target: gl::GLuint,
+}
+
+#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
+pub struct ProgramId(pub gl::GLuint);
+
+#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
+pub struct VAOId(gl::GLuint);
+
+#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
+pub struct FBOId(gl::GLuint);
+
+#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
+pub struct VBOId(gl::GLuint);
+
+#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
+struct IBOId(gl::GLuint);
+
+#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
+pub struct UBOId(gl::GLuint);
+
+const MAX_EVENTS_PER_FRAME: usize = 256;
+const MAX_PROFILE_FRAMES: usize = 4;
+
+pub trait NamedTag {
+    fn get_label(&self) -> &str;
+}
+
+#[derive(Debug, Clone)]
+pub struct GpuSample<T> {
+    pub tag: T,
+    pub time_ns: u64,
+}
+
+pub struct GpuFrameProfile<T> {
+    queries: Vec<gl::GLuint>,
+    samples: Vec<GpuSample<T>>,
+    next_query: usize,
+    pending_query: gl::GLuint,
+}
+
+impl<T> GpuFrameProfile<T> {
+    #[cfg(not(target_os = "android"))]
+    fn new() -> GpuFrameProfile<T> {
+        let queries = gl::gen_queries(MAX_EVENTS_PER_FRAME as gl::GLint);
+
+        GpuFrameProfile {
+            queries: queries,
+            samples: Vec::new(),
+            next_query: 0,
+            pending_query: 0,
+        }
+    }
+
+    #[cfg(target_os = "android")]
+    fn new() -> GpuFrameProfile<T> {
+        GpuFrameProfile {
+            queries: Vec::new(),
+            samples: Vec::new(),
+            next_query: 0,
+            pending_query: 0,
+        }
+    }
+
+    fn begin_frame(&mut self) {
+        self.next_query = 0;
+        self.pending_query = 0;
+        self.samples.clear();
+    }
+
+    #[cfg(not(target_os = "android"))]
+    fn end_frame(&mut self) {
+        if self.pending_query != 0 {
+            gl::end_query(gl::TIME_ELAPSED);
+        }
+    }
+
+    #[cfg(target_os = "android")]
+    fn end_frame(&mut self) {
+    }
+
+    #[cfg(not(target_os = "android"))]
+    fn add_marker(&mut self, tag: T) -> GpuMarker
+    where T: NamedTag {
+        if self.pending_query != 0 {
+            gl::end_query(gl::TIME_ELAPSED);
+        }
+
+        let marker = GpuMarker::new(tag.get_label());
+
+        if self.next_query < MAX_EVENTS_PER_FRAME {
+            self.pending_query = self.queries[self.next_query];
+            gl::begin_query(gl::TIME_ELAPSED, self.pending_query);
+            self.samples.push(GpuSample {
+                tag: tag,
+                time_ns: 0,
+            });
+        } else {
+            self.pending_query = 0;
+        }
+
+        self.next_query += 1;
+        marker
+    }
+
+    #[cfg(target_os = "android")]
+    fn add_marker(&mut self, tag: T) {
+        self.samples.push(GpuSample {
+            tag: tag,
+            time_ns: 0,
+        });
+    }
+
+    fn is_valid(&self) -> bool {
+        self.next_query <= MAX_EVENTS_PER_FRAME
+    }
+
+    #[cfg(not(target_os = "android"))]
+    fn build_samples(&mut self) -> Vec<GpuSample<T>> {
+        for (index, sample) in self.samples.iter_mut().enumerate() {
+            sample.time_ns = gl::get_query_object_ui64v(self.queries[index], gl::QUERY_RESULT)
+        }
+
+        mem::replace(&mut self.samples, Vec::new())
+    }
+
+    #[cfg(target_os = "android")]
+    fn build_samples(&mut self) -> Vec<GpuSample<T>> {
+        mem::replace(&mut self.samples, Vec::new())
+    }
+}
+
+impl<T> Drop for GpuFrameProfile<T> {
+    #[cfg(not(target_os = "android"))]
+    fn drop(&mut self) {
+        gl::delete_queries(&self.queries);
+    }
+
+    #[cfg(target_os = "android")]
+    fn drop(&mut self) {
+    }
+}
+
+pub struct GpuProfiler<T> {
+    frames: [GpuFrameProfile<T>; MAX_PROFILE_FRAMES],
+    next_frame: usize,
+}
+
+impl<T> GpuProfiler<T> {
+    pub fn new() -> GpuProfiler<T> {
+        GpuProfiler {
+            next_frame: 0,
+            frames: [
+                      GpuFrameProfile::new(),
+                      GpuFrameProfile::new(),
+                      GpuFrameProfile::new(),
+                      GpuFrameProfile::new(),
+                    ],
+        }
+    }
+
+    pub fn build_samples(&mut self) -> Option<Vec<GpuSample<T>>> {
+        let frame = &mut self.frames[self.next_frame];
+        if frame.is_valid() {
+            Some(frame.build_samples())
+        } else {
+            None
+        }
+    }
+
+    pub fn begin_frame(&mut self) {
+        let frame = &mut self.frames[self.next_frame];
+        frame.begin_frame();
+    }
+
+    pub fn end_frame(&mut self) {
+        let frame = &mut self.frames[self.next_frame];
+        frame.end_frame();
+        self.next_frame = (self.next_frame + 1) % MAX_PROFILE_FRAMES;
+    }
+
+    #[cfg(not(target_os = "android"))]
+    pub fn add_marker(&mut self, tag: T) -> GpuMarker
+    where T: NamedTag {
+        self.frames[self.next_frame].add_marker(tag)
+    }
+
+    #[cfg(target_os = "android")]
+    pub fn add_marker(&mut self, tag: T) {
+        self.frames[self.next_frame].add_marker(tag)
+    }
+}
+
+#[must_use]
+pub struct GpuMarker(());
+
+#[cfg(any(target_arch="arm", target_arch="aarch64"))]
+impl GpuMarker {
+    pub fn new(_: &str) -> GpuMarker {
+        GpuMarker(())
+    }
+
+    pub fn fire(_: &str) {}
+}
+
+
+#[cfg(not(any(target_arch="arm", target_arch="aarch64")))]
+impl GpuMarker {
+    pub fn new(message: &str) -> GpuMarker {
+       gl::push_group_marker_ext(message);
+       GpuMarker(())
+    }
+
+    pub fn fire(message: &str) {
+        gl::insert_event_marker_ext(message);
+    }
+}
+
+#[cfg(not(any(target_arch="arm", target_arch="aarch64")))]
+impl Drop for GpuMarker {
+    fn drop(&mut self) {
+        gl::pop_group_marker_ext();
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub enum VertexUsageHint {
+    Static,
+    Dynamic,
+    Stream,
+}
+
+impl VertexUsageHint {
+    fn to_gl(&self) -> gl::GLuint {
+        match *self {
+            VertexUsageHint::Static => gl::STATIC_DRAW,
+            VertexUsageHint::Dynamic => gl::DYNAMIC_DRAW,
+            VertexUsageHint::Stream => gl::STREAM_DRAW,
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug)]
+pub struct UniformLocation(gl::GLint);
+
+impl UniformLocation {
+    pub fn invalid() -> UniformLocation {
+        UniformLocation(-1)
+    }
+}
+
+// TODO(gw): Fix up notify cargo deps and re-enable this!
+/*
+enum FileWatcherCmd {
+    AddWatch(PathBuf),
+    Exit,
+}
+
+struct FileWatcherThread {
+    api_tx: Sender<FileWatcherCmd>,
+}
+
+impl FileWatcherThread {
+    fn new(handler: Box<FileWatcherHandler>) -> FileWatcherThread {
+        let (api_tx, api_rx) = channel();
+
+        thread::spawn(move || {
+
+            let (watch_tx, watch_rx) = channel();
+
+            enum Request {
+                Watcher(notify::Event),
+                Command(FileWatcherCmd),
+            }
+
+            let mut file_watcher: notify::RecommendedWatcher = notify::Watcher::new(watch_tx).unwrap();
+
+            loop {
+                let request = {
+                    let receiver_from_api = &api_rx;
+                    let receiver_from_watcher = &watch_rx;
+                    select! {
+                        msg = receiver_from_api.recv() => Request::Command(msg.unwrap()),
+                        msg = receiver_from_watcher.recv() => Request::Watcher(msg.unwrap())
+                    }
+                };
+
+                match request {
+                    Request::Watcher(event) => {
+                        handler.file_changed(event.path.unwrap());
+                    }
+                    Request::Command(cmd) => {
+                        match cmd {
+                            FileWatcherCmd::AddWatch(path) => {
+                                file_watcher.watch(path).ok();
+                            }
+                            FileWatcherCmd::Exit => {
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        });
+
+        FileWatcherThread {
+            api_tx: api_tx,
+        }
+    }
+
+    fn exit(&self) {
+        self.api_tx.send(FileWatcherCmd::Exit).ok();
+    }
+
+    fn add_watch(&self, path: PathBuf) {
+        self.api_tx.send(FileWatcherCmd::AddWatch(path)).ok();
+    }
+}
+*/
+
+pub struct Capabilities {
+    pub max_ubo_size: usize,
+    pub supports_multisampling: bool,
+}
+
+pub struct Device {
+    // device state
+    bound_textures: [TextureId; 16],
+    bound_program: ProgramId,
+    bound_vao: VAOId,
+    bound_read_fbo: FBOId,
+    bound_draw_fbo: FBOId,
+    default_read_fbo: gl::GLuint,
+    default_draw_fbo: gl::GLuint,
+    device_pixel_ratio: f32,
+
+    // HW or API capabilties
+    capabilities: Capabilities,
+
+    // debug
+    inside_frame: bool,
+
+    // resources
+    resource_override_path: Option<PathBuf>,
+    textures: HashMap<TextureId, Texture, BuildHasherDefault<FnvHasher>>,
+    programs: HashMap<ProgramId, Program, BuildHasherDefault<FnvHasher>>,
+    vaos: HashMap<VAOId, VAO, BuildHasherDefault<FnvHasher>>,
+
+    // misc.
+    shader_preamble: String,
+    //file_watcher: FileWatcherThread,
+
+    // Used on android only
+    #[allow(dead_code)]
+    next_vao_id: gl::GLuint,
+}
+
+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);
+        //file_watcher.add_watch(resource_path);
+
+        Device {
+            resource_override_path: resource_override_path,
+            // This is initialized to 1 by default, but it is set
+            // every frame by the call to begin_frame().
+            device_pixel_ratio: 1.0,
+            inside_frame: false,
+
+            capabilities: Capabilities {
+                max_ubo_size: gl::get_integer_v(gl::MAX_UNIFORM_BLOCK_SIZE) as usize,
+                supports_multisampling: false, //TODO
+            },
+
+            bound_textures: [ TextureId::invalid(); 16 ],
+            bound_program: ProgramId(0),
+            bound_vao: VAOId(0),
+            bound_read_fbo: FBOId(0),
+            bound_draw_fbo: FBOId(0),
+            default_read_fbo: 0,
+            default_draw_fbo: 0,
+
+            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,
+        }
+    }
+
+    pub fn get_capabilities(&self) -> &Capabilities {
+        &self.capabilities
+    }
+
+    pub fn compile_shader(name: &str,
+                          source_str: &str,
+                          shader_type: gl::GLenum,
+                          shader_preamble: &[String],
+                          panic_on_fail: bool)
+                          -> Option<gl::GLuint> {
+        debug!("compile {:?}", name);
+
+        let mut s = String::new();
+        s.push_str(SHADER_VERSION);
+        for prefix in shader_preamble {
+            s.push_str(&prefix);
+        }
+        s.push_str(source_str);
+
+        let id = gl::create_shader(shader_type);
+        let mut source = Vec::new();
+        source.extend_from_slice(s.as_bytes());
+        gl::shader_source(id, &[&source[..]]);
+        gl::compile_shader(id);
+        let log = gl::get_shader_info_log(id);
+        if gl::get_shader_iv(id, gl::COMPILE_STATUS) == (0 as gl::GLint) {
+            println!("Failed to compile shader: {:?}\n{}", name, log);
+            if panic_on_fail {
+                panic!("-- Shader compile failed - exiting --");
+            }
+
+            None
+        } else {
+            if !log.is_empty() {
+                println!("Warnings detected on shader: {:?}\n{}", name, log);
+            }
+            Some(id)
+        }
+    }
+
+    pub fn begin_frame(&mut self, device_pixel_ratio: f32) {
+        debug_assert!(!self.inside_frame);
+        self.inside_frame = true;
+        self.device_pixel_ratio = device_pixel_ratio;
+
+        // Retrive the currently set FBO.
+        let default_read_fbo = gl::get_integer_v(gl::READ_FRAMEBUFFER_BINDING);
+        self.default_read_fbo = default_read_fbo as gl::GLuint;
+        let default_draw_fbo = gl::get_integer_v(gl::DRAW_FRAMEBUFFER_BINDING);
+        self.default_draw_fbo = default_draw_fbo as gl::GLuint;
+
+        // Texture state
+        for i in 0..self.bound_textures.len() {
+            self.bound_textures[i] = TextureId::invalid();
+            gl::active_texture(gl::TEXTURE0 + i as gl::GLuint);
+            gl::bind_texture(gl::TEXTURE_2D, 0);
+        }
+
+        // Shader state
+        self.bound_program = ProgramId(0);
+        gl::use_program(0);
+
+        // Vertex state
+        self.bound_vao = VAOId(0);
+        self.clear_vertex_array();
+
+        // FBO state
+        self.bound_read_fbo = FBOId(self.default_read_fbo);
+        self.bound_draw_fbo = FBOId(self.default_draw_fbo);
+
+        // Pixel op state
+        gl::pixel_store_i(gl::UNPACK_ALIGNMENT, 1);
+
+        // Default is sampler 0, always
+        gl::active_texture(gl::TEXTURE0);
+    }
+
+    pub fn bind_texture(&mut self,
+                        sampler: TextureSampler,
+                        texture_id: TextureId) {
+        debug_assert!(self.inside_frame);
+
+        let sampler_index = sampler as usize;
+        if self.bound_textures[sampler_index] != texture_id {
+            self.bound_textures[sampler_index] = texture_id;
+            gl::active_texture(gl::TEXTURE0 + sampler_index as gl::GLuint);
+            texture_id.bind();
+            gl::active_texture(gl::TEXTURE0);
+        }
+    }
+
+    pub fn bind_read_target(&mut self, texture_id: Option<(TextureId, i32)>) {
+        debug_assert!(self.inside_frame);
+
+        let fbo_id = texture_id.map_or(FBOId(self.default_read_fbo), |texture_id| {
+            self.textures.get(&texture_id.0).unwrap().fbo_ids[texture_id.1 as usize]
+        });
+
+        if self.bound_read_fbo != fbo_id {
+            self.bound_read_fbo = fbo_id;
+            fbo_id.bind(FBOTarget::Read);
+        }
+    }
+
+    pub fn bind_draw_target(&mut self,
+                            texture_id: Option<(TextureId, i32)>,
+                            dimensions: Option<ViewportDimensions>) {
+        debug_assert!(self.inside_frame);
+
+        let fbo_id = texture_id.map_or(FBOId(self.default_draw_fbo), |texture_id| {
+            self.textures.get(&texture_id.0).unwrap().fbo_ids[texture_id.1 as usize]
+        });
+
+        if self.bound_draw_fbo != fbo_id {
+            self.bound_draw_fbo = fbo_id;
+            fbo_id.bind(FBOTarget::Draw);
+        }
+
+        if let Some(dimensions) = dimensions {
+            gl::viewport(0, 0, dimensions[0] as gl::GLint, dimensions[1] as gl::GLint);
+        }
+    }
+
+    pub fn bind_program(&mut self,
+                        program_id: ProgramId,
+                        projection: &Matrix4D<f32>) {
+        debug_assert!(self.inside_frame);
+
+        if self.bound_program != program_id {
+            self.bound_program = program_id;
+            program_id.bind();
+        }
+
+        let program = self.programs.get(&program_id).unwrap();
+        self.set_uniforms(program,
+                          projection,
+                          self.device_pixel_ratio);
+    }
+
+    pub fn create_texture_ids(&mut self,
+                              count: i32,
+                              target: TextureTarget) -> Vec<TextureId> {
+        let id_list = gl::gen_textures(count);
+        let mut texture_ids = Vec::new();
+
+        let target = match target {
+            TextureTarget::Default => gl::TEXTURE_2D,
+            TextureTarget::Array => gl::TEXTURE_2D_ARRAY,
+        };
+
+        for id in id_list {
+            let texture_id = TextureId {
+                name: id,
+                target: target,
+            };
+
+            let texture = Texture {
+                id: id,
+                width: 0,
+                height: 0,
+                format: ImageFormat::Invalid,
+                filter: TextureFilter::Nearest,
+                mode: RenderTargetMode::None,
+                fbo_ids: vec![],
+            };
+
+            debug_assert!(self.textures.contains_key(&texture_id) == false);
+            self.textures.insert(texture_id, texture);
+
+            texture_ids.push(texture_id);
+        }
+
+        texture_ids
+    }
+
+    pub fn get_texture_dimensions(&self, texture_id: TextureId) -> (u32, u32) {
+        let texture = &self.textures[&texture_id];
+        (texture.width, texture.height)
+    }
+
+    fn set_texture_parameters(&mut self, target: gl::GLuint, filter: TextureFilter) {
+        let filter = match filter {
+            TextureFilter::Nearest => {
+                gl::NEAREST
+            }
+            TextureFilter::Linear => {
+                gl::LINEAR
+            }
+        };
+
+        gl::tex_parameter_i(target, gl::TEXTURE_MAG_FILTER, filter as gl::GLint);
+        gl::tex_parameter_i(target, gl::TEXTURE_MIN_FILTER, filter as gl::GLint);
+
+        gl::tex_parameter_i(target, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as gl::GLint);
+        gl::tex_parameter_i(target, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as gl::GLint);
+    }
+
+    fn upload_texture_image(&mut self,
+                            target: gl::GLuint,
+                            width: u32,
+                            height: u32,
+                            internal_format: u32,
+                            format: u32,
+                            type_: u32,
+                            pixels: Option<&[u8]>) {
+        gl::tex_image_2d(target,
+                         0,
+                         internal_format as gl::GLint,
+                         width as gl::GLint, height as gl::GLint,
+                         0,
+                         format,
+                         type_,
+                         pixels);
+    }
+
+    pub fn init_texture(&mut self,
+                        texture_id: TextureId,
+                        width: u32,
+                        height: u32,
+                        format: ImageFormat,
+                        filter: TextureFilter,
+                        mode: RenderTargetMode,
+                        pixels: Option<&[u8]>) {
+        debug_assert!(self.inside_frame);
+
+        {
+            let texture = self.textures.get_mut(&texture_id).expect("Didn't find texture!");
+            texture.format = format;
+            texture.width = width;
+            texture.height = height;
+            texture.filter = filter;
+            texture.mode = mode;
+        }
+
+        let (internal_format, gl_format) = gl_texture_formats_for_image_format(format);
+        let type_ = gl_type_for_texture_format(format);
+
+        match mode {
+            RenderTargetMode::SimpleRenderTarget => {
+                self.bind_texture(DEFAULT_TEXTURE, texture_id);
+                self.set_texture_parameters(texture_id.target, filter);
+                self.upload_texture_image(texture_id.target,
+                                          width,
+                                          height,
+                                          internal_format as u32,
+                                          gl_format,
+                                          type_,
+                                          None);
+                self.create_fbo_for_texture_if_necessary(texture_id, None);
+            }
+            RenderTargetMode::LayerRenderTarget(layer_count) => {
+                self.bind_texture(DEFAULT_TEXTURE, texture_id);
+                self.set_texture_parameters(texture_id.target, filter);
+                self.create_fbo_for_texture_if_necessary(texture_id, Some(layer_count));
+            }
+            RenderTargetMode::None => {
+                self.bind_texture(DEFAULT_TEXTURE, texture_id);
+                self.set_texture_parameters(texture_id.target, filter);
+                self.upload_texture_image(texture_id.target,
+                                          width,
+                                          height,
+                                          internal_format as u32,
+                                          gl_format,
+                                          type_,
+                                          pixels);
+            }
+        }
+    }
+
+    pub fn get_render_target_layer_count(&self, texture_id: TextureId) -> usize {
+        self.textures[&texture_id].fbo_ids.len()
+    }
+
+    pub fn create_fbo_for_texture_if_necessary(&mut self,
+                                               texture_id: TextureId,
+                                               layer_count: Option<i32>) {
+        let texture = self.textures.get_mut(&texture_id).unwrap();
+
+        match layer_count {
+            Some(layer_count) => {
+                debug_assert!(layer_count > 0);
+
+                // If we have enough layers allocated already, just use them.
+                // TODO(gw): Probably worth removing some after a while if
+                //           there is a surplus?
+                let current_layer_count = texture.fbo_ids.len() as i32;
+                if current_layer_count >= layer_count {
+                    return;
+                }
+
+                let (internal_format, gl_format) = gl_texture_formats_for_image_format(texture.format);
+                let type_ = gl_type_for_texture_format(texture.format);
+
+                gl::tex_image_3d(texture_id.target,
+                                 0,
+                                 internal_format as gl::GLint,
+                                 texture.width as gl::GLint,
+                                 texture.height as gl::GLint,
+                                 layer_count,
+                                 0,
+                                 gl_format,
+                                 type_,
+                                 None);
+
+                let needed_layer_count = layer_count - current_layer_count;
+                let new_fbos = gl::gen_framebuffers(needed_layer_count);
+                texture.fbo_ids.extend(new_fbos.into_iter().map(|id| FBOId(id)));
+
+                for (fbo_index, fbo_id) in texture.fbo_ids.iter().enumerate() {
+                    gl::bind_framebuffer(gl::FRAMEBUFFER, fbo_id.0);
+                    gl::framebuffer_texture_layer(gl::FRAMEBUFFER,
+                                                  gl::COLOR_ATTACHMENT0,
+                                                  texture_id.name,
+                                                  0,
+                                                  fbo_index as gl::GLint);
+
+                    // TODO(gw): Share depth render buffer between FBOs to
+                    //           save memory!
+                    // TODO(gw): Free these renderbuffers on exit!
+                    let renderbuffer_ids = gl::gen_renderbuffers(1);
+                    let depth_rb = renderbuffer_ids[0];
+                    gl::bind_renderbuffer(gl::RENDERBUFFER, depth_rb);
+                    gl::renderbuffer_storage(gl::RENDERBUFFER,
+                                             gl::DEPTH_COMPONENT24,
+                                             texture.width as gl::GLsizei,
+                                             texture.height as gl::GLsizei);
+                    gl::framebuffer_renderbuffer(gl::FRAMEBUFFER,
+                                                 gl::DEPTH_ATTACHMENT,
+                                                 gl::RENDERBUFFER,
+                                                 depth_rb);
+                }
+            }
+            None => {
+                debug_assert!(texture.fbo_ids.len() == 0 || texture.fbo_ids.len() == 1);
+                if texture.fbo_ids.is_empty() {
+                    let new_fbo = gl::gen_framebuffers(1)[0];
+
+                    gl::bind_framebuffer(gl::FRAMEBUFFER, new_fbo);
+
+                    gl::framebuffer_texture_2d(gl::FRAMEBUFFER,
+                                               gl::COLOR_ATTACHMENT0,
+                                               texture_id.target,
+                                               texture_id.name,
+                                               0);
+
+                    texture.fbo_ids.push(FBOId(new_fbo));
+                }
+            }
+        }
+
+        // TODO(gw): Hack! Modify the code above to use the normal binding interfaces the device exposes.
+        gl::bind_framebuffer(gl::READ_FRAMEBUFFER, self.bound_read_fbo.0);
+        gl::bind_framebuffer(gl::DRAW_FRAMEBUFFER, self.bound_draw_fbo.0);
+    }
+
+    pub fn blit_render_target(&mut self,
+                              src_texture: Option<(TextureId, i32)>,
+                              src_rect: Option<DeviceIntRect>,
+                              dest_rect: DeviceIntRect) {
+        debug_assert!(self.inside_frame);
+
+        let src_rect = src_rect.unwrap_or_else(|| {
+            let texture = self.textures.get(&src_texture.unwrap().0).expect("unknown texture id!");
+            DeviceIntRect::new(DeviceIntPoint::zero(),
+                               DeviceIntSize::new(texture.width as gl::GLint,
+                                                  texture.height as gl::GLint))
+        });
+
+        self.bind_read_target(src_texture);
+
+        gl::blit_framebuffer(src_rect.origin.x,
+                             src_rect.origin.y,
+                             src_rect.origin.x + src_rect.size.width,
+                             src_rect.origin.y + src_rect.size.height,
+                             dest_rect.origin.x,
+                             dest_rect.origin.y,
+                             dest_rect.origin.x + dest_rect.size.width,
+                             dest_rect.origin.y + dest_rect.size.height,
+                             gl::COLOR_BUFFER_BIT,
+                             gl::LINEAR);
+    }
+
+    pub fn resize_texture(&mut self,
+                          texture_id: TextureId,
+                          new_width: u32,
+                          new_height: u32,
+                          format: ImageFormat,
+                          filter: TextureFilter,
+                          mode: RenderTargetMode) {
+        debug_assert!(self.inside_frame);
+
+        let (old_width, old_height) = self.get_texture_dimensions(texture_id);
+
+        let temp_texture_id = self.create_texture_ids(1, TextureTarget::Default)[0];
+        self.init_texture(temp_texture_id, old_width, old_height, format, filter, mode, None);
+        self.create_fbo_for_texture_if_necessary(temp_texture_id, None);
+
+        self.bind_read_target(Some((texture_id, 0)));
+        self.bind_texture(DEFAULT_TEXTURE, temp_texture_id);
+
+        gl::copy_tex_sub_image_2d(temp_texture_id.target,
+                                  0,
+                                  0,
+                                  0,
+                                  0,
+                                  0,
+                                  old_width as i32,
+                                  old_height as i32);
+
+        self.deinit_texture(texture_id);
+        self.init_texture(texture_id, new_width, new_height, format, filter, mode, None);
+        self.create_fbo_for_texture_if_necessary(texture_id, None);
+        self.bind_read_target(Some((temp_texture_id, 0)));
+        self.bind_texture(DEFAULT_TEXTURE, texture_id);
+
+        gl::copy_tex_sub_image_2d(texture_id.target,
+                                  0,
+                                  0,
+                                  0,
+                                  0,
+                                  0,
+                                  old_width as i32,
+                                  old_height as i32);
+
+        self.bind_read_target(None);
+        self.deinit_texture(temp_texture_id);
+    }
+
+    pub fn deinit_texture(&mut self, texture_id: TextureId) {
+        debug_assert!(self.inside_frame);
+
+        self.bind_texture(DEFAULT_TEXTURE, texture_id);
+
+        let texture = self.textures.get_mut(&texture_id).unwrap();
+        let (internal_format, gl_format) = gl_texture_formats_for_image_format(texture.format);
+        let type_ = gl_type_for_texture_format(texture.format);
+
+        gl::tex_image_2d(texture_id.target,
+                         0,
+                         internal_format,
+                         0,
+                         0,
+                         0,
+                         gl_format,
+                         type_,
+                         None);
+
+        if !texture.fbo_ids.is_empty() {
+            let fbo_ids: Vec<_> = texture.fbo_ids.iter().map(|&FBOId(fbo_id)| fbo_id).collect();
+            gl::delete_framebuffers(&fbo_ids[..]);
+        }
+
+        texture.format = ImageFormat::Invalid;
+        texture.width = 0;
+        texture.height = 0;
+        texture.fbo_ids.clear();
+    }
+
+    pub fn create_program(&mut self,
+                          base_filename: &str,
+                          include_filename: &str) -> ProgramId {
+        self.create_program_with_prefix(base_filename, &[include_filename], None)
+    }
+
+    pub fn create_program_with_prefix(&mut self,
+                                      base_filename: &str,
+                                      include_filenames: &[&str],
+                                      prefix: Option<String>) -> ProgramId {
+        debug_assert!(self.inside_frame);
+
+        let pid = gl::create_program();
+
+        let mut vs_name = String::from(base_filename);
+        vs_name.push_str(".vs");
+        let mut fs_name = String::from(base_filename);
+        fs_name.push_str(".fs");
+
+        let mut include = format!("// Base shader: {}\n", base_filename);
+        for inc_filename in include_filenames {
+            let src = get_shader_source(inc_filename, &self.resource_override_path);
+            include.push_str(&src);
+        }
+
+        if let Some(shared_src) = get_optional_shader_source(base_filename, &self.resource_override_path) {
+            include.push_str(&shared_src);
+        }
+
+        let program = Program {
+            name: base_filename.to_owned(),
+            id: pid,
+            u_transform: -1,
+            u_device_pixel_ratio: -1,
+            vs_source: get_shader_source(&vs_name, &self.resource_override_path),
+            fs_source: get_shader_source(&fs_name, &self.resource_override_path),
+            prefix: prefix,
+            vs_id: None,
+            fs_id: None,
+        };
+
+        let program_id = ProgramId(pid);
+
+        debug_assert!(self.programs.contains_key(&program_id) == false);
+        self.programs.insert(program_id, program);
+
+        self.load_program(program_id, include, true);
+
+        program_id
+    }
+
+    fn load_program(&mut self,
+                    program_id: ProgramId,
+                    include: String,
+                    panic_on_fail: bool) {
+        debug_assert!(self.inside_frame);
+
+        let program = self.programs.get_mut(&program_id).unwrap();
+
+        let mut vs_preamble = Vec::new();
+        let mut fs_preamble = Vec::new();
+
+        vs_preamble.push("#define WR_VERTEX_SHADER\n".to_owned());
+        fs_preamble.push("#define WR_FRAGMENT_SHADER\n".to_owned());
+
+        if let Some(ref prefix) = program.prefix {
+            vs_preamble.push(prefix.clone());
+            fs_preamble.push(prefix.clone());
+        }
+
+        vs_preamble.push(self.shader_preamble.to_owned());
+        fs_preamble.push(self.shader_preamble.to_owned());
+
+        vs_preamble.push(include.clone());
+        fs_preamble.push(include);
+
+        // todo(gw): store shader ids so they can be freed!
+        let vs_id = Device::compile_shader(&program.name,
+                                           &program.vs_source,
+                                           gl::VERTEX_SHADER,
+                                           &vs_preamble,
+                                           panic_on_fail);
+        let fs_id = Device::compile_shader(&program.name,
+                                           &program.fs_source,
+                                           gl::FRAGMENT_SHADER,
+                                           &fs_preamble,
+                                           panic_on_fail);
+
+        match (vs_id, fs_id) {
+            (Some(vs_id), None) => {
+                println!("FAILED to load fs - falling back to previous!");
+                gl::delete_shader(vs_id);
+            }
+            (None, Some(fs_id)) => {
+                println!("FAILED to load vs - falling back to previous!");
+                gl::delete_shader(fs_id);
+            }
+            (None, None) => {
+                println!("FAILED to load vs/fs - falling back to previous!");
+            }
+            (Some(vs_id), Some(fs_id)) => {
+                if let Some(vs_id) = program.vs_id {
+                    gl::detach_shader(program.id, vs_id);
+                }
+
+                if let Some(fs_id) = program.fs_id {
+                    gl::detach_shader(program.id, fs_id);
+                }
+
+                if program.attach_and_bind_shaders(vs_id, fs_id, panic_on_fail) {
+                    if let Some(vs_id) = program.vs_id {
+                        gl::delete_shader(vs_id);
+                    }
+
+                    if let Some(fs_id) = program.fs_id {
+                        gl::delete_shader(fs_id);
+                    }
+
+                    program.vs_id = Some(vs_id);
+                    program.fs_id = Some(fs_id);
+                } else {
+                    let vs_id = program.vs_id.unwrap();
+                    let fs_id = program.fs_id.unwrap();
+                    program.attach_and_bind_shaders(vs_id, fs_id, true);
+                }
+
+                program.u_transform = gl::get_uniform_location(program.id, "uTransform");
+                program.u_device_pixel_ratio = gl::get_uniform_location(program.id, "uDevicePixelRatio");
+
+                program_id.bind();
+                let u_color_0 = gl::get_uniform_location(program.id, "sColor0");
+                if u_color_0 != -1 {
+                    gl::uniform_1i(u_color_0, TextureSampler::Color0 as i32);
+                }
+                let u_color1 = gl::get_uniform_location(program.id, "sColor1");
+                if u_color1 != -1 {
+                    gl::uniform_1i(u_color1, TextureSampler::Color1 as i32);
+                }
+                let u_color_2 = gl::get_uniform_location(program.id, "sColor2");
+                if u_color_2 != -1 {
+                    gl::uniform_1i(u_color_2, TextureSampler::Color2 as i32);
+                }
+                let u_mask = gl::get_uniform_location(program.id, "sMask");
+                if u_mask != -1 {
+                    gl::uniform_1i(u_mask, TextureSampler::Mask as i32);
+                }
+
+                let u_cache = gl::get_uniform_location(program.id, "sCache");
+                if u_cache != -1 {
+                    gl::uniform_1i(u_cache, TextureSampler::Cache as i32);
+                }
+
+                let u_layers = gl::get_uniform_location(program.id, "sLayers");
+                if u_layers != -1 {
+                    gl::uniform_1i(u_layers, TextureSampler::Layers as i32);
+                }
+
+                let u_tasks = gl::get_uniform_location(program.id, "sRenderTasks");
+                if u_tasks != -1 {
+                    gl::uniform_1i(u_tasks, TextureSampler::RenderTasks as i32);
+                }
+
+                let u_prim_geom = gl::get_uniform_location(program.id, "sPrimGeometry");
+                if u_prim_geom != -1 {
+                    gl::uniform_1i(u_prim_geom, TextureSampler::Geometry as i32);
+                }
+
+                let u_data16 = gl::get_uniform_location(program.id, "sData16");
+                if u_data16 != -1 {
+                    gl::uniform_1i(u_data16, TextureSampler::Data16 as i32);
+                }
+
+                let u_data32 = gl::get_uniform_location(program.id, "sData32");
+                if u_data32 != -1 {
+                    gl::uniform_1i(u_data32, TextureSampler::Data32 as i32);
+                }
+
+                let u_data64 = gl::get_uniform_location(program.id, "sData64");
+                if u_data64 != -1 {
+                    gl::uniform_1i(u_data64, TextureSampler::Data64 as i32);
+                }
+
+                let u_data128 = gl::get_uniform_location(program.id, "sData128");
+                if u_data128 != -1 {
+                    gl::uniform_1i(u_data128, TextureSampler::Data128    as i32);
+                }
+
+                let u_resource_rects = gl::get_uniform_location(program.id, "sResourceRects");
+                if u_resource_rects != -1 {
+                    gl::uniform_1i(u_resource_rects, TextureSampler::ResourceRects as i32);
+                }
+            }
+        }
+    }
+
+/*
+    pub fn refresh_shader(&mut self, path: PathBuf) {
+        let mut vs_preamble_path = self.resource_path.clone();
+        vs_preamble_path.push(VERTEX_SHADER_PREAMBLE);
+
+        let mut fs_preamble_path = self.resource_path.clone();
+        fs_preamble_path.push(FRAGMENT_SHADER_PREAMBLE);
+
+        let mut refresh_all = false;
+
+        if path == vs_preamble_path {
+            let mut f = File::open(&vs_preamble_path).unwrap();
+            self.vertex_shader_preamble = String::new();
+            f.read_to_string(&mut self.vertex_shader_preamble).unwrap();
+            refresh_all = true;
+        }
+
+        if path == fs_preamble_path {
+            let mut f = File::open(&fs_preamble_path).unwrap();
+            self.fragment_shader_preamble = String::new();
+            f.read_to_string(&mut self.fragment_shader_preamble).unwrap();
+            refresh_all = true;
+        }
+
+        let mut programs_to_update = Vec::new();
+
+        for (program_id, program) in &mut self.programs {
+            if refresh_all || program.vs_path == path || program.fs_path == path {
+                programs_to_update.push(*program_id)
+            }
+        }
+
+        for program_id in programs_to_update {
+            self.load_program(program_id, false);
+        }
+    }*/
+
+    pub fn get_uniform_location(&self, program_id: ProgramId, name: &str) -> UniformLocation {
+        let ProgramId(program_id) = program_id;
+        UniformLocation(gl::get_uniform_location(program_id, name))
+    }
+
+    pub fn set_uniform_2f(&self, uniform: UniformLocation, x: f32, y: f32) {
+        debug_assert!(self.inside_frame);
+        let UniformLocation(location) = uniform;
+        gl::uniform_2f(location, x, y);
+    }
+
+    fn set_uniforms(&self,
+                    program: &Program,
+                    transform: &Matrix4D<f32>,
+                    device_pixel_ratio: f32) {
+        debug_assert!(self.inside_frame);
+        gl::uniform_matrix_4fv(program.u_transform,
+                               false,
+                               &transform.to_row_major_array());
+        gl::uniform_1f(program.u_device_pixel_ratio, device_pixel_ratio);
+    }
+
+    fn update_image_for_2d_texture(&mut self,
+                                   target: gl::GLuint,
+                                   x0: gl::GLint,
+                                   y0: gl::GLint,
+                                   width: gl::GLint,
+                                   height: gl::GLint,
+                                   format: gl::GLuint,
+                                   data: &[u8]) {
+        gl::tex_sub_image_2d(target,
+                             0,
+                             x0, y0,
+                             width, height,
+                             format,
+                             gl::UNSIGNED_BYTE,
+                             data);
+    }
+
+    pub fn update_texture(&mut self,
+                          texture_id: TextureId,
+                          x0: u32,
+                          y0: u32,
+                          width: u32,
+                          height: u32,
+                          stride: Option<u32>,
+                          data: &[u8]) {
+        debug_assert!(self.inside_frame);
+
+        let mut expanded_data = Vec::new();
+
+        let (gl_format, bpp, data) = match self.textures.get(&texture_id).unwrap().format {
+            ImageFormat::A8 => {
+                if cfg!(any(target_arch="arm", target_arch="aarch64")) {
+                    for byte in data {
+                        expanded_data.push(*byte);
+                        expanded_data.push(*byte);
+                        expanded_data.push(*byte);
+                        expanded_data.push(*byte);
+                    }
+                    (GL_FORMAT_BGRA, 4, expanded_data.as_slice())
+                } else {
+                    (GL_FORMAT_A, 1, data)
+                }
+            }
+            ImageFormat::RGB8 => (gl::RGB, 3, data),
+            ImageFormat::RGBA8 => (GL_FORMAT_BGRA, 4, data),
+            ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(),
+        };
+
+        let row_length = match stride {
+            Some(value) => value / bpp,
+            None => width,
+        };
+
+        assert!(data.len() as u32 == bpp * row_length * height);
+
+        if let Some(..) = stride {
+            gl::pixel_store_i(gl::UNPACK_ROW_LENGTH, row_length as gl::GLint);
+        }
+
+        self.bind_texture(DEFAULT_TEXTURE, texture_id);
+        self.update_image_for_2d_texture(texture_id.target,
+                                         x0 as gl::GLint,
+                                         y0 as gl::GLint,
+                                         width as gl::GLint,
+                                         height as gl::GLint,
+                                         gl_format,
+                                         data);
+
+        // Reset row length to 0, otherwise the stride would apply to all texture uploads.
+        if let Some(..) = stride {
+            gl::pixel_store_i(gl::UNPACK_ROW_LENGTH, 0 as gl::GLint);
+        }
+    }
+
+    fn clear_vertex_array(&mut self) {
+        debug_assert!(self.inside_frame);
+        gl::bind_vertex_array(0);
+    }
+
+    pub fn bind_vao(&mut self, vao_id: VAOId) {
+        debug_assert!(self.inside_frame);
+
+        if self.bound_vao != vao_id {
+            self.bound_vao = vao_id;
+
+            let VAOId(id) = vao_id;
+            gl::bind_vertex_array(id);
+        }
+    }
+
+    fn create_vao_with_vbos(&mut self,
+                            format: VertexFormat,
+                            main_vbo_id: VBOId,
+                            instance_vbo_id: VBOId,
+                            ibo_id: IBOId,
+                            vertex_offset: gl::GLuint,
+                            instance_stride: gl::GLint,
+                            owns_vertices: bool,
+                            owns_instances: bool,
+                            owns_indices: bool)
+                            -> VAOId {
+        debug_assert!(self.inside_frame);
+
+        let vao_ids = gl::gen_vertex_arrays(1);
+        let vao_id = vao_ids[0];
+
+        gl::bind_vertex_array(vao_id);
+
+        format.bind(main_vbo_id, instance_vbo_id, vertex_offset, instance_stride);
+        ibo_id.bind(); // force it to be a part of VAO
+
+        let vao = VAO {
+            id: vao_id,
+            ibo_id: ibo_id,
+            main_vbo_id: main_vbo_id,
+            instance_vbo_id: instance_vbo_id,
+            instance_stride: instance_stride,
+            owns_indices: owns_indices,
+            owns_vertices: owns_vertices,
+            owns_instances: owns_instances,
+        };
+
+        gl::bind_vertex_array(0);
+
+        let vao_id = VAOId(vao_id);
+
+        debug_assert!(!self.vaos.contains_key(&vao_id));
+        self.vaos.insert(vao_id, vao);
+
+        vao_id
+    }
+
+    pub fn create_vao(&mut self, format: VertexFormat, inst_stride: gl::GLint) -> VAOId {
+        debug_assert!(self.inside_frame);
+
+        let buffer_ids = gl::gen_buffers(3);
+        let ibo_id = IBOId(buffer_ids[0]);
+        let main_vbo_id = VBOId(buffer_ids[1]);
+        let intance_vbo_id = VBOId(buffer_ids[2]);
+
+        self.create_vao_with_vbos(format, main_vbo_id, intance_vbo_id, ibo_id, 0, inst_stride, true, true, true)
+    }
+
+    pub fn create_vao_with_new_instances(&mut self, format: VertexFormat, inst_stride: gl::GLint,
+                                         base_vao: VAOId) -> VAOId {
+        debug_assert!(self.inside_frame);
+
+        let buffer_ids = gl::gen_buffers(1);
+        let intance_vbo_id = VBOId(buffer_ids[0]);
+        let (main_vbo_id, ibo_id) = {
+            let vao = self.vaos.get(&base_vao).unwrap();
+            (vao.main_vbo_id, vao.ibo_id)
+        };
+
+        self.create_vao_with_vbos(format, main_vbo_id, intance_vbo_id, ibo_id, 0, inst_stride, false, true, false)
+    }
+
+    pub fn update_vao_main_vertices<V>(&mut self,
+                                       vao_id: VAOId,
+                                       vertices: &[V],
+                                       usage_hint: VertexUsageHint) {
+        debug_assert!(self.inside_frame);
+
+        let vao = self.vaos.get(&vao_id).unwrap();
+        debug_assert_eq!(self.bound_vao, vao_id);
+
+        vao.main_vbo_id.bind();
+        gl::buffer_data(gl::ARRAY_BUFFER, &vertices, usage_hint.to_gl());
+    }
+
+    pub fn update_vao_instances<V>(&mut self,
+                                   vao_id: VAOId,
+                                   instances: &[V],
+                                   usage_hint: VertexUsageHint) {
+        debug_assert!(self.inside_frame);
+
+        let vao = self.vaos.get(&vao_id).unwrap();
+        debug_assert_eq!(self.bound_vao, vao_id);
+        debug_assert_eq!(vao.instance_stride as usize, mem::size_of::<V>());
+
+        vao.instance_vbo_id.bind();
+        gl::buffer_data(gl::ARRAY_BUFFER, &instances, usage_hint.to_gl());
+    }
+
+    pub fn update_vao_indices<I>(&mut self,
+                                 vao_id: VAOId,
+                                 indices: &[I],
+                                 usage_hint: VertexUsageHint) {
+        debug_assert!(self.inside_frame);
+
+        let vao = self.vaos.get(&vao_id).unwrap();
+        debug_assert_eq!(self.bound_vao, vao_id);
+
+        vao.ibo_id.bind();
+        gl::buffer_data(gl::ELEMENT_ARRAY_BUFFER, &indices, usage_hint.to_gl());
+    }
+
+    pub fn draw_triangles_u16(&mut self, first_vertex: i32, index_count: i32) {
+        debug_assert!(self.inside_frame);
+        gl::draw_elements(gl::TRIANGLES,
+                          index_count,
+                          gl::UNSIGNED_SHORT,
+                          first_vertex as u32 * 2);
+    }
+
+    pub fn draw_triangles_u32(&mut self, first_vertex: i32, index_count: i32) {
+        debug_assert!(self.inside_frame);
+        gl::draw_elements(gl::TRIANGLES,
+                          index_count,
+                          gl::UNSIGNED_INT,
+                          first_vertex as u32 * 4);
+    }
+
+    pub fn draw_nonindexed_lines(&mut self, first_vertex: i32, vertex_count: i32) {
+        debug_assert!(self.inside_frame);
+        gl::draw_arrays(gl::LINES,
+                          first_vertex,
+                          vertex_count);
+    }
+
+    pub fn draw_indexed_triangles_instanced_u16(&mut self,
+                                                index_count: i32,
+                                                instance_count: i32) {
+        debug_assert!(self.inside_frame);
+        gl::draw_elements_instanced(gl::TRIANGLES, index_count, gl::UNSIGNED_SHORT, 0, instance_count);
+    }
+
+    pub fn end_frame(&mut self) {
+        self.bind_draw_target(None, None);
+        self.bind_read_target(None);
+
+        debug_assert!(self.inside_frame);
+        self.inside_frame = false;
+
+        gl::bind_texture(gl::TEXTURE_2D, 0);
+        gl::use_program(0);
+
+        for i in 0..self.bound_textures.len() {
+            gl::active_texture(gl::TEXTURE0 + i as gl::GLuint);
+            gl::bind_texture(gl::TEXTURE_2D, 0);
+        }
+
+        gl::active_texture(gl::TEXTURE0);
+    }
+
+    pub fn assign_ubo_binding(&self, program_id: ProgramId, name: &str, value: u32) -> u32 {
+        let index = gl::get_uniform_block_index(program_id.0, name);
+        gl::uniform_block_binding(program_id.0, index, value);
+        index
+    }
+
+    pub fn create_ubo<T>(&self, data: &[T], binding: u32) -> UBOId {
+        let ubo = gl::gen_buffers(1)[0];
+        gl::bind_buffer(gl::UNIFORM_BUFFER, ubo);
+        gl::buffer_data(gl::UNIFORM_BUFFER, data, gl::STATIC_DRAW);
+        gl::bind_buffer_base(gl::UNIFORM_BUFFER, binding, ubo);
+        UBOId(ubo)
+    }
+
+    pub fn reset_ubo(&self, binding: u32) {
+        gl::bind_buffer(gl::UNIFORM_BUFFER, 0);
+        gl::bind_buffer_base(gl::UNIFORM_BUFFER, binding, 0);
+    }
+
+    pub fn delete_buffer(&self, buffer: UBOId) {
+        gl::delete_buffers(&[buffer.0]);
+    }
+
+    #[cfg(target_os = "android")]
+    pub fn set_multisample(&self, enable: bool) {
+    }
+
+    #[cfg(not(target_os = "android"))]
+    pub fn set_multisample(&self, enable: bool) {
+        if self.capabilities.supports_multisampling {
+            if enable {
+                gl::enable(gl::MULTISAMPLE);
+            } else {
+                gl::disable(gl::MULTISAMPLE);
+            }
+        }
+    }
+
+    pub fn clear_target(&self,
+                        color: Option<[f32; 4]>,
+                        depth: Option<f32>) {
+        let mut clear_bits = 0;
+
+        if let Some(color) = color {
+            gl::clear_color(color[0], color[1], color[2], color[3]);
+            clear_bits |= gl::COLOR_BUFFER_BIT;
+        }
+
+        if let Some(depth) = depth {
+            gl::clear_depth(depth as f64);
+            clear_bits |= gl::DEPTH_BUFFER_BIT;
+        }
+
+        if clear_bits != 0 {
+            gl::clear(clear_bits);
+        }
+    }
+
+    pub fn enable_depth(&self) {
+        gl::enable(gl::DEPTH_TEST);
+    }
+
+    pub fn disable_depth(&self) {
+        gl::disable(gl::DEPTH_TEST);
+    }
+
+    pub fn set_depth_func(&self, depth_func: DepthFunction) {
+        gl::depth_func(depth_func as gl::GLuint);
+    }
+
+    pub fn enable_depth_write(&self) {
+        gl::depth_mask(true);
+    }
+
+    pub fn disable_depth_write(&self) {
+        gl::depth_mask(false);
+    }
+
+    pub fn disable_stencil(&self) {
+        gl::disable(gl::STENCIL_TEST);
+    }
+
+    pub fn disable_scissor(&self) {
+        gl::disable(gl::SCISSOR_TEST);
+    }
+
+    pub fn set_blend(&self, enable: bool) {
+        if enable {
+            gl::enable(gl::BLEND);
+        } else {
+            gl::disable(gl::BLEND);
+        }
+    }
+
+    pub fn set_blend_mode_premultiplied_alpha(&self) {
+        gl::blend_func(gl::SRC_ALPHA, gl::ZERO);
+        gl::blend_equation(gl::FUNC_ADD);
+    }
+
+    pub fn set_blend_mode_alpha(&self) {
+        //gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
+        gl::blend_func_separate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA,
+                                gl::ONE, gl::ONE);
+        gl::blend_equation(gl::FUNC_ADD);
+    }
+
+    pub fn set_blend_mode_subpixel(&self, color: ColorF) {
+        gl::blend_color(color.r, color.g, color.b, color.a);
+        gl::blend_func(gl::CONSTANT_COLOR, gl::ONE_MINUS_SRC_COLOR);
+    }
+
+    pub fn set_blend_mode_multiply(&self) {
+        gl::blend_func_separate(gl::ZERO, gl::SRC_COLOR,
+                                gl::ZERO, gl::SRC_ALPHA);
+        gl::blend_equation(gl::FUNC_ADD);
+    }
+}
+
+impl Drop for Device {
+    fn drop(&mut self) {
+        //self.file_watcher.exit();
+    }
+}
+
+fn gl_texture_formats_for_image_format(format: ImageFormat) -> (gl::GLint, gl::GLuint) {
+    match format {
+        ImageFormat::A8 => {
+            if cfg!(any(target_arch="arm", target_arch="aarch64")) {
+                (GL_FORMAT_BGRA as gl::GLint, GL_FORMAT_BGRA)
+            } else {
+                (GL_FORMAT_A as gl::GLint, GL_FORMAT_A)
+            }
+        },
+        ImageFormat::RGB8 => (gl::RGB as gl::GLint, gl::RGB),
+        ImageFormat::RGBA8 => {
+            if cfg!(any(target_arch="arm", target_arch="aarch64")) {
+                (GL_FORMAT_BGRA as gl::GLint, GL_FORMAT_BGRA)
+            } else {
+                (gl::RGBA as gl::GLint, GL_FORMAT_BGRA)
+            }
+        }
+        ImageFormat::RGBAF32 => (gl::RGBA32F as gl::GLint, gl::RGBA),
+        ImageFormat::Invalid => unreachable!(),
+    }
+}
+
+fn gl_type_for_texture_format(format: ImageFormat) -> gl::GLuint {
+    match format {
+        ImageFormat::RGBAF32 => gl::FLOAT,
+        _ => gl::UNSIGNED_BYTE,
+    }
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/src/frame.rs
@@ -0,0 +1,660 @@
+/* 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 fnv::FnvHasher;
+use internal_types::{ANGLE_FLOAT_TO_FIXED, AxisDirection};
+use internal_types::{CompositionOp};
+use internal_types::{LowLevelFilterOp};
+use internal_types::{RendererFrame};
+use layer::Layer;
+use resource_cache::ResourceCache;
+use scene::Scene;
+use scroll_tree::{ScrollTree, ScrollStates};
+use std::collections::HashMap;
+use std::hash::BuildHasherDefault;
+use tiling::{AuxiliaryListsMap, FrameBuilder, FrameBuilderConfig, PrimitiveFlags};
+use webrender_traits::{AuxiliaryLists, ClipRegion, ColorF, DisplayItem, Epoch, FilterOp};
+use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform};
+use webrender_traits::{MixBlendMode, PipelineId, ScrollEventPhase, ScrollLayerId, ScrollLayerState};
+use webrender_traits::{ScrollLocation, ScrollPolicy, ServoScrollRootId, SpecificDisplayItem};
+use webrender_traits::{StackingContext, WorldPoint};
+
+#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
+pub struct FrameId(pub u32);
+
+static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF { r: 0.3, g: 0.3, b: 0.3, a: 0.6 };
+
+struct FlattenContext<'a> {
+    scene: &'a Scene,
+    pipeline_sizes: &'a mut HashMap<PipelineId, LayerSize>,
+    builder: &'a mut FrameBuilder,
+}
+
+// TODO: doc
+pub struct Frame {
+    pub scroll_tree: ScrollTree,
+    pub pipeline_epoch_map: HashMap<PipelineId, Epoch, BuildHasherDefault<FnvHasher>>,
+    pub pipeline_auxiliary_lists: AuxiliaryListsMap,
+    id: FrameId,
+    debug: bool,
+    frame_builder_config: FrameBuilderConfig,
+    frame_builder: Option<FrameBuilder>,
+}
+
+trait DisplayListHelpers {
+    fn starting_stacking_context<'a>(&'a self) -> Option<(&'a StackingContext, &'a ClipRegion)>;
+}
+
+impl DisplayListHelpers for Vec<DisplayItem> {
+    fn starting_stacking_context<'a>(&'a self) -> Option<(&'a StackingContext, &'a ClipRegion)> {
+        self.first().and_then(|item| match item.item {
+            SpecificDisplayItem::PushStackingContext(ref specific_item) => {
+                Some((&specific_item.stacking_context, &item.clip))
+            },
+            _ => None,
+        })
+    }
+}
+
+trait StackingContextHelpers {
+    fn needs_composition_operation_for_mix_blend_mode(&self) -> bool;
+    fn composition_operations(&self, auxiliary_lists: &AuxiliaryLists) -> Vec<CompositionOp>;
+}
+
+impl StackingContextHelpers for StackingContext {
+    fn needs_composition_operation_for_mix_blend_mode(&self) -> bool {
+        match self.mix_blend_mode {
+            MixBlendMode::Normal => false,
+            MixBlendMode::Multiply |
+            MixBlendMode::Screen |
+            MixBlendMode::Overlay |
+            MixBlendMode::Darken |
+            MixBlendMode::Lighten |
+            MixBlendMode::ColorDodge |
+            MixBlendMode::ColorBurn |
+            MixBlendMode::HardLight |
+            MixBlendMode::SoftLight |
+            MixBlendMode::Difference |
+            MixBlendMode::Exclusion |
+            MixBlendMode::Hue |
+            MixBlendMode::Saturation |
+            MixBlendMode::Color |
+            MixBlendMode::Luminosity => true,
+        }
+    }
+
+    fn composition_operations(&self, auxiliary_lists: &AuxiliaryLists) -> Vec<CompositionOp> {
+        let mut composition_operations = vec![];
+        if self.needs_composition_operation_for_mix_blend_mode() {
+            composition_operations.push(CompositionOp::MixBlend(self.mix_blend_mode));
+        }
+        for filter in auxiliary_lists.filters(&self.filters) {
+            match *filter {
+                FilterOp::Blur(radius) => {
+                    composition_operations.push(CompositionOp::Filter(LowLevelFilterOp::Blur(
+                        radius,
+                        AxisDirection::Horizontal)));
+                    composition_operations.push(CompositionOp::Filter(LowLevelFilterOp::Blur(
+                        radius,
+                        AxisDirection::Vertical)));
+                }
+                FilterOp::Brightness(amount) => {
+                    composition_operations.push(CompositionOp::Filter(
+                            LowLevelFilterOp::Brightness(Au::from_f32_px(amount))));
+                }
+                FilterOp::Contrast(amount) => {
+                    composition_operations.push(CompositionOp::Filter(
+                            LowLevelFilterOp::Contrast(Au::from_f32_px(amount))));
+                }
+                FilterOp::Grayscale(amount) => {
+                    composition_operations.push(CompositionOp::Filter(
+                            LowLevelFilterOp::Grayscale(Au::from_f32_px(amount))));
+                }
+                FilterOp::HueRotate(angle) => {
+                    composition_operations.push(CompositionOp::Filter(
+                            LowLevelFilterOp::HueRotate(f32::round(
+                                    angle * ANGLE_FLOAT_TO_FIXED) as i32)));
+                }
+                FilterOp::Invert(amount) => {
+                    composition_operations.push(CompositionOp::Filter(
+                            LowLevelFilterOp::Invert(Au::from_f32_px(amount))));
+                }
+                FilterOp::Opacity(amount) => {
+                    composition_operations.push(CompositionOp::Filter(
+                            LowLevelFilterOp::Opacity(Au::from_f32_px(amount))));
+                }
+                FilterOp::Saturate(amount) => {
+                    composition_operations.push(CompositionOp::Filter(
+                            LowLevelFilterOp::Saturate(Au::from_f32_px(amount))));
+                }
+                FilterOp::Sepia(amount) => {
+                    composition_operations.push(CompositionOp::Filter(
+                            LowLevelFilterOp::Sepia(Au::from_f32_px(amount))));
+                }
+            }
+        }
+
+        composition_operations
+    }
+}
+
+struct DisplayListTraversal<'a> {
+    pub display_list: &'a [DisplayItem],
+    pub next_item_index: usize,
+}
+
+impl<'a> DisplayListTraversal<'a> {
+    pub fn new_skipping_first(display_list: &'a Vec<DisplayItem>) -> DisplayListTraversal {
+        DisplayListTraversal {
+            display_list: display_list,
+            next_item_index: 1,
+        }
+    }
+
+    pub fn skip_current_stacking_context(&mut self) {
+        for item in self {
+            if item.item == SpecificDisplayItem::PopStackingContext {
+                return;
+            }
+        }
+    }
+
+    pub fn current_stacking_context_empty(&self) -> bool {
+        match self.peek() {
+            Some(item) => item.item == SpecificDisplayItem::PopStackingContext,
+            None => true,
+        }
+    }
+
+    fn peek(&self) -> Option<&'a DisplayItem> {
+        if self.next_item_index >= self.display_list.len() {
+            return None
+        }
+        Some(&self.display_list[self.next_item_index])
+    }
+}
+
+impl<'a> Iterator for DisplayListTraversal<'a> {
+    type Item = &'a DisplayItem;
+
+    fn next(&mut self) -> Option<&'a DisplayItem> {
+        if self.next_item_index >= self.display_list.len() {
+            return None
+        }
+
+        let item = &self.display_list[self.next_item_index];
+        self.next_item_index += 1;
+        Some(item)
+    }
+}
+
+impl Frame {
+    pub fn new(debug: bool, config: FrameBuilderConfig) -> Frame {
+        Frame {
+            pipeline_epoch_map: HashMap::with_hasher(Default::default()),
+            pipeline_auxiliary_lists: HashMap::with_hasher(Default::default()),
+            scroll_tree: ScrollTree::new(),
+            id: FrameId(0),
+            debug: debug,
+            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()
+    }
+
+    pub fn get_scroll_layer_state(&self) -> Vec<ScrollLayerState> {
+        self.scroll_tree.get_scroll_layer_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 layers 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,)
+    }
+
+    pub fn tick_scrolling_bounce_animations(&mut self) {
+        self.scroll_tree.tick_scrolling_bounce_animations();
+    }
+
+    pub fn create(&mut self,
+                  scene: &Scene,
+                  pipeline_sizes: &mut HashMap<PipelineId, LayerSize>) {
+        let root_pipeline_id = match scene.root_pipeline_id {
+            Some(root_pipeline_id) => root_pipeline_id,
+            None => return,
+        };
+
+        let root_pipeline = match scene.pipeline_map.get(&root_pipeline_id) {
+            Some(root_pipeline) => root_pipeline,
+            None => return,
+        };
+
+        let display_list = scene.display_lists.get(&root_pipeline_id);
+        let display_list = match display_list {
+            Some(display_list) => display_list,
+            None => return,
+        };
+
+        let old_scrolling_states = self.reset();
+        self.pipeline_auxiliary_lists = scene.pipeline_auxiliary_lists.clone();
+
+        self.pipeline_epoch_map.insert(root_pipeline_id, root_pipeline.epoch);
+
+        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;
+            }
+        };
+
+        // Insert global position: fixed elements layer
+        debug_assert!(self.scroll_tree.layers.is_empty());
+        let root_scroll_layer_id = ScrollLayerId::root(root_pipeline_id);
+        let root_fixed_layer_id = ScrollLayerId::create_fixed(root_pipeline_id);
+        let root_viewport = LayerRect::new(LayerPoint::zero(), root_pipeline.viewport_size);
+        let layer = Layer::new(&root_viewport,
+                               root_clip.main.size,
+                               &LayerToScrollTransform::identity(),
+                               root_pipeline_id);
+        self.scroll_tree.add_layer(layer.clone(), root_fixed_layer_id, None);
+        self.scroll_tree.add_layer(layer, root_scroll_layer_id, None);
+        self.scroll_tree.root_scroll_layer_id = Some(root_scroll_layer_id);
+
+        let background_color = root_pipeline.background_color.and_then(|color| {
+            if color.a > 0.0 {
+                Some(color)
+            } else {
+                None
+            }
+        });
+
+        let mut frame_builder = FrameBuilder::new(root_pipeline.viewport_size,
+                                                  background_color,
+                                                  self.debug,
+                                                  self.frame_builder_config);
+
+        {
+            let mut context = FlattenContext {
+                scene: scene,
+                pipeline_sizes: pipeline_sizes,
+                builder: &mut frame_builder,
+            };
+
+            let mut traversal = DisplayListTraversal::new_skipping_first(display_list);
+            self.flatten_stacking_context(&mut traversal,
+                                          root_pipeline_id,
+                                          &mut context,
+                                          root_fixed_layer_id,
+                                          root_scroll_layer_id,
+                                          LayerToScrollTransform::identity(),
+                                          0,
+                                          &root_stacking_context,
+                                          root_clip);
+        }
+
+        self.frame_builder = Some(frame_builder);
+        self.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_fixed_layer_id: ScrollLayerId,
+                                mut current_scroll_layer_id: ScrollLayerId,
+                                layer_relative_transform: LayerToScrollTransform,
+                                level: i32,
+                                clip: &LayerRect,
+                                content_size: &LayerSize,
+