Fix search results being clipped in app list.
[chromium-blink-merge.git] / ui / accessibility / extensions / colorenhancer / src / cvd.js
blob12b2d904239372462088368f407b9819852142f1
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 // ======= Global state =======
8 var storedDelta = 0;
9 var storedSeverity = 0;
10 var storedType = 'PROTANOMALY';
11 var storedSimulate = false;
12 var curFilter = 0;
15 // ======= 3x3 matrix ops =======
17 var identityMatrix3x3 = [
18   [1, 0, 0],
19   [0, 1, 0],
20   [0, 0, 1]
24 /**
25  * TODO(mustaq): JsDoc
26  */
27 function add3x3(m1, m2) {
28     var result = [];
29     for (var i = 0; i < 3; i++) {
30         result[i] = [];
31         for (var j = 0; j < 3; j++) {
32             result[i].push(m1[i][j] + m2[i][j]);
33         }
34     }
35     return result;
39 /**
40  * TODO(mustaq): JsDoc
41  */
42 function sub3x3(m1, m2) {
43     var result = [];
44     for (var i = 0; i < 3; i++) {
45         result[i] = [];
46         for (var j = 0; j < 3; j++) {
47             result[i].push(m1[i][j] - m2[i][j]);
48         }
49     }
50     return result;
54 /**
55  * TODO(mustaq): JsDoc
56  */
57 function mul3x3(m1, m2) {
58     var result = [];
59     for (var i = 0; i < 3; i++) {
60         result[i] = [];
61         for (var j = 0; j < 3; j++) {
62             var sum = 0;
63             for (var k = 0; k < 3; k++) {
64                 sum += m1[i][k] * m2[k][j];
65             }
66             result[i].push(sum);
67         }
68     }
69     return result;
73 /**
74  * TODO(mustaq): JsDoc
75  */
76 function mul3x3Scalar(m, k) {
77     var result = [];
78     for (var i = 0; i < 3; i++) {
79         result[i] = [];
80         for (var j = 0; j < 3; j++) {
81             result[i].push(k * m[i][j]);
82         }
83     }
84     return result;
88 // ======= CVD parameters =======
89 /**
90  * Parameters for simulating color vision deficiency.
91  * Source:
92  *     http://www.inf.ufrgs.br/~oliveira/pubs_files/CVD_Simulation/CVD_Simulation.html
93  * Original Research Paper:
94  *     http://www.inf.ufrgs.br/~oliveira/pubs_files/CVD_Simulation/Machado_Oliveira_Fernandes_CVD_Vis2009_final.pdf
95  *
96  * @enum {string}
97  */
98 var cvdSimulationParams = {
99   PROTANOMALY: [
100     [0.4720, -1.2946, 0.9857],
101     [-0.6128, 1.6326, 0.0187],
102     [0.1407, -0.3380, -0.0044],
103     [-0.1420, 0.2488, 0.0044],
104     [0.1872, -0.3908, 0.9942],
105     [-0.0451, 0.1420, 0.0013],
106     [0.0222, -0.0253, -0.0004],
107     [-0.0290, -0.0201, 0.0006],
108     [0.0068, 0.0454, 0.9990]
109   ],
110   DEUTERANOMALY: [
111     [0.5442, -1.1454, 0.9818],
112     [-0.7091, 1.5287, 0.0238],
113     [0.1650, -0.3833, -0.0055],
114     [-0.1664, 0.4368, 0.0056],
115     [0.2178, -0.5327, 0.9927],
116     [-0.0514, 0.0958, 0.0017],
117     [0.0180, -0.0288, -0.0006],
118     [-0.0232, -0.0649, 0.0007],
119     [0.0052, 0.0360, 0.9998]
120   ],
121   TRITANOMALY: [
122     [0.4275, -0.0181, 0.9307],
123     [-0.2454, 0.0013, 0.0827],
124     [-0.1821, 0.0168, -0.0134],
125     [-0.1280, 0.0047, 0.0202],
126     [0.0233, -0.0398, 0.9728],
127     [0.1048, 0.0352, 0.0070],
128     [-0.0156, 0.0061, 0.0071],
129     [0.3841, 0.2947, 0.0151],
130     [-0.3685, -0.3008, 0.9778]
131   ]
135 // TODO(mustaq): A common matrix for all types? E.g. Kevin's experiment
136 //   suggested: Mx[1][0] = 0.7+0.3*delta and Mx[2][0] = 0.7-0.3*delta
138  * TODO(mustaq): JsDoc
140  * @enum {string}
141  */
142 var cvdCorrectionParams = {
143   PROTANOMALY: {
144     addendum: [
145       [-1.0, 0.0, 0.0],
146       [0.5, 1.0, 0.0],
147       [1.5, 0.0, 1.0]
148     ],
149     delta_factor: [
150       [0.0, 0.0, 0.0],
151       [1.0, 0.0, 0.0],
152       [-1.0, 0.0, 0.0]
153     ]
154   },
155   DEUTERANOMALY: {
156     addendum: [
157       [1.0, 0.5, 0.0],
158       [0.5, -1.0, 0.0],
159       [1.5, 1.5, 1.0]
160     ],
161     delta_factor: [
162       [0.0, 1.0, 0.0],
163       [0.0, 0.0, 0.0],
164       [0.0, -1.0, 0.0]
165     ]
166   },
167   TRITANOMALY: {
168     addendum: [
169       [1.0, 0.0, 1.5],
170       [0.0, 1.0, 0.5],
171       [0.0, 0.0, -1.0]
172     ],
173     delta_factor: [
174       [0.0, 0.0, -1.0],
175       [0.0, 0.0, 1.0],
176       [0.0, 0.0, 0.0]
177     ]
178   }
182 // =======  CVD matrix builders =======
185  * TODO(mustaq): JsDoc
186  */
187 function getCvdSimulationMatrix(cvdType, severity) {
188   var cvdSimulationParam = cvdSimulationParams[cvdType];
189   var severity2 = severity * severity;
190   var matrix = [];
191   for (var i = 0; i < 3; i++) {
192     var row = [];
193     for (var j = 0; j < 3; j++) {
194       var paramRow = i*3+j;
195       var val = cvdSimulationParam[paramRow][0] * severity2
196               + cvdSimulationParam[paramRow][1] * severity
197               + cvdSimulationParam[paramRow][2];
198       row.push(val);
199     }
200     matrix.push(row);
201   }
202   return matrix;
207  * TODO(mustaq): JsDoc
208  */
209 function getCvdCorrectionMatrix(cvdType, delta) {
210   cvdCorrectionParam = cvdCorrectionParams[cvdType];
211   // TODO(mustaq): Perhaps nuke full-matrix operations after experiment.
212   return add3x3(cvdCorrectionParam['addendum'],
213                 mul3x3Scalar(cvdCorrectionParam['delta_factor'], delta));
218  * TODO(mustaq): JsDoc
219  */
220 function getCvdMatrixAsString(cvdType, severity, delta, simulate) {
221   var effectiveMatrix = getCvdSimulationMatrix(cvdType, severity);
223   if (!simulate) {
224     var cvdCorrectionMatrix = getCvdCorrectionMatrix(cvdType, delta);
225     var tmpProduct = mul3x3(cvdCorrectionMatrix, effectiveMatrix);
227     effectiveMatrix = sub3x3(
228         add3x3(identityMatrix3x3, cvdCorrectionMatrix),
229         tmpProduct);
230   }
232   var outputRows = [];
233   for (var i = 0; i < 3; i++) {
234     outputRows.push(effectiveMatrix[i].join(' ') + ' 0 0');
235   }
236   // Add the alpha row
237   outputRows.push('0 0 0 1 0');
238   return outputRows.join(' ');
242 // ======= Page linker =======
244 var svgDefaultMatrix =
245   '1 0 0 0 0 ' +
246   '0 1 0 0 0 ' +
247   '0 0 1 0 0 ' +
248   '0 0 0 1 0';
250 var svgContent =
251   '<svg xmlns='http://www.w3.org/2000/svg' version='1.1'>' +
252   '  <defs>' +
253   '    <filter id='cvd_extension_0'>' +
254   '      <feColorMatrix id='cvd_filter_matrix_0' type='matrix' values='' +
255   svgDefaultMatrix + ''/>' +
256   '    </filter>' +
257   '    <filter id='cvd_extension_1'>' +
258   '      <feColorMatrix id='cvd_filter_matrix_1' type='matrix' values='' +
259   svgDefaultMatrix + ''/>' +
260   '    </filter>' +
261   '  </defs>' +
262   '</svg>';
265  * Checks for svg filter matrix presence and append to DOM if not present.
266  */
267 function addSvgIfMissing() {
268   var wrap = document.getElementById('cvd_extension_svg_filter');
269   if (!wrap) {
270     wrap = document.createElement('span');
271     wrap.id = 'cvd_extension_svg_filter';
272     wrap.setAttribute('hidden', '');
273     wrap.innerHTML = svgContent;
274     document.body.appendChild(wrap);
275   }
280  * Update matrix when config values change.
281  */
282 function update() {
283   if (!document.body) {
284     document.addEventListener('DOMContentLoaded', update);
285     return;
286   }
287   addSvgIfMissing();
288   var next = 1 - curFilter;
290   debugPrint(
291       'Setting matrix#' + next + ' to ' +
292       getCvdMatrixAsString(
293           storedType, storedSeverity, storedDelta, storedSimulate));
295   var matrix = document.getElementById('cvd_filter_matrix_' + next);
296   matrix.setAttribute(
297       'values', getCvdMatrixAsString(
298           storedType, storedSeverity, storedDelta, storedSimulate));
300   var html = document.documentElement;
301   html.classList.remove('filter' + curFilter);
302   html.offsetTop;
303   html.classList.add('filter' + next);
305   curFilter = next;
307   // TODO(wnwen): Figure out whether this hack is still necessary.
308   window.scrollBy(0, 1);
309   window.scrollBy(0, -1);
314  * Process request from background page.
315  */
316 function onExtensionMessage(request) {
317   var changed = false;
319   if (request['delta'] !== undefined) {
320     var delta = request.delta;
321     if (storedDelta != delta) {
322       storedDelta = delta;
323       changed = true;
324     }
325   }
327   if (request['severity'] !== undefined) {
328     var severity = request.severity;
329     if (storedSeverity != severity) {
330       storedSeverity = severity;
331       changed = true;
332     }
333   }
335   if (request['type'] !== undefined) {
336     var type = request.type;
337     if (storedType != type) {
338       storedType = type;
339       changed = true;
340     }
341   }
343   if (request['simulate'] !== undefined) {
344     var simulate = request.simulate;
345     if (storedSimulate != simulate) {
346       storedSimulate = simulate;
347       changed = true;
348     }
349   }
351   if (changed)
352     update();
357  * Prepare to process background messages and let it know to send initial
358  * values.
359  */
360 (function initialize() {
361   chrome.extension.onRequest.addListener(onExtensionMessage);
362   chrome.extension.sendRequest({'init': true}, onExtensionMessage);
363 })();