author | Kartikaya Gupta <kgupta@mozilla.com> |
Mon, 06 Feb 2017 11:42:52 -0500 | |
changeset 340979 | bafbb19be9a460d896e0d065843e5507610b6171 |
parent 340978 | 7f1b358fb17dfd982c5e18c34d5735cd481c7f7c |
child 340980 | 7fa68c2685b2d3fe239e7118a55aae852e56beed |
push id | 86615 |
push user | kwierso@gmail.com |
push date | Tue, 07 Feb 2017 01:52:08 +0000 |
treeherder | mozilla-inbound@f0453084d86e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | gfx |
bugs | 1335525 |
milestone | 54.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
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) + } +}