| OLD | NEW |
| 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 var mode; | 5 var mode; |
| 6 var enabled = false; | 6 var enabled = false; |
| 7 var scheme = ''; | 7 var scheme = ''; |
| 8 var timeoutId = null; | 8 var timeoutId = null; |
| 9 | 9 |
| 10 var filterMap = { | 10 var filterMap = { |
| 11 '0': 'url("#hc_extension_off")', | 11 '0': 'url("#hc_extension_off")', |
| 12 '1': 'url("#hc_extension_highcontrast")', | 12 '1': 'url("#hc_extension_highcontrast")', |
| 13 '2': 'url("#hc_extension_grayscale")', | 13 '2': 'url("#hc_extension_grayscale")', |
| 14 '3': 'url("#hc_extension_invert")', | 14 '3': 'url("#hc_extension_invert")', |
| 15 '4': 'url("#hc_extension_invert_grayscale")', | 15 '4': 'url("#hc_extension_invert_grayscale")', |
| 16 '5': 'url("#hc_extension_yellow_on_black")' | 16 '5': 'url("#hc_extension_yellow_on_black")' |
| 17 }; | 17 }; |
| 18 | 18 |
| 19 var svgContent = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1"><defs><f
ilter id="hc_extension_off"><feComponentTransfer><feFuncR type="table" tableValu
es="0 1"/><feFuncG type="table" tableValues="0 1"/><feFuncB type="table" tableVa
lues="0 1"/></feComponentTransfer></filter><filter id="hc_extension_highcontrast
"><feComponentTransfer><feFuncR type="gamma" exponent="3.0"/><feFuncG type="gamm
a" exponent="3.0"/><feFuncB type="gamma" exponent="3.0"/></feComponentTransfer><
/filter><filter id="hc_extension_highcontrast_back"><feComponentTransfer><feFunc
R type="gamma" exponent="0.33"/><feFuncG type="gamma" exponent="0.33"/><feFuncB
type="gamma" exponent="0.33"/></feComponentTransfer></filter><filter id="hc_exte
nsion_grayscale"><feColorMatrix type="matrix" values="0.2126 0.7152 0.0722 0 0 0
.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0 0 0 0 0 1 0"/><feComponentTransfe
r><feFuncR type="gamma" exponent="3"/><feFuncG type="gamma" exponent="3"/><feFun
cB type="gamma" exponent="3"/></feComponentTransfer></filter><filter id="hc_exte
nsion_grayscale_back"><feComponentTransfer><feFuncR type="gamma" exponent="0.33"
/><feFuncG type="gamma" exponent="0.33"/><feFuncB type="gamma" exponent="0.33"/>
</feComponentTransfer></filter><filter id="hc_extension_invert"><feComponentTran
sfer><feFuncR type="gamma" amplitude="-1" exponent="3" offset="1"/><feFuncG type
="gamma" amplitude="-1" exponent="3" offset="1"/><feFuncB type="gamma" amplitude
="-1" exponent="3" offset="1"/></feComponentTransfer></filter><filter id="hc_ext
ension_invert_back"><feComponentTransfer><feFuncR type="table" tableValues="1 0"
/><feFuncG type="table" tableValues="1 0"/><feFuncB type="table" tableValues="1
0"/></feComponentTransfer><feComponentTransfer><feFuncR type="gamma" exponent="1
.7"/><feFuncG type="gamma" exponent="1.7"/><feFuncB type="gamma" exponent="1.7"/
></feComponentTransfer></filter><filter id="hc_extension_invert_grayscale"><feCo
lorMatrix type="matrix" values="0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0
0 0.2126 0.7152 0.0722 0 0 0 0 0 1 0"/><feComponentTransfer><feFuncR type="gamma
" amplitude="-1" exponent="3" offset="1"/><feFuncG type="gamma" amplitude="-1" e
xponent="3" offset="1"/><feFuncB type="gamma" amplitude="-1" exponent="3" offset
="1"/></feComponentTransfer></filter><filter id="hc_extension_yellow_on_black"><
feComponentTransfer><feFuncR type="gamma" amplitude="-1" exponent="3" offset="1"
/><feFuncG type="gamma" amplitude="-1" exponent="3" offset="1"/><feFuncB type="g
amma" amplitude="-1" exponent="3" offset="1"/></feComponentTransfer><feColorMatr
ix type="matrix" values="0.3 0.5 0.2 0 0 0.3 0.5 0.2 0 0 0 0 0 0 0 0 0 0 1 0"/><
/filter><filter id="hc_extension_yellow_on_black_back"><feComponentTransfer><feF
uncR type="table" tableValues="1 0"/><feFuncG type="table" tableValues="1 0"/><f
eFuncB type="table" tableValues="1 0"/></feComponentTransfer><feComponentTransfe
r><feFuncR type="gamma" exponent="0.33"/><feFuncG type="gamma" exponent="0.33"/>
<feFuncB type="gamma" exponent="0.33"/></feComponentTransfer></filter></defs></s
vg>'; | 19 var svgContent = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1"><defs><f
ilter x="0" y="0" width="99999" height="99999" id="hc_extension_off"><feComponen
tTransfer><feFuncR type="table" tableValues="0 1"/><feFuncG type="table" tableVa
lues="0 1"/><feFuncB type="table" tableValues="0 1"/></feComponentTransfer></fil
ter><filter x="0" y="0" width="99999" height="99999" id="hc_extension_highcontra
st"><feComponentTransfer><feFuncR type="gamma" exponent="3.0"/><feFuncG type="ga
mma" exponent="3.0"/><feFuncB type="gamma" exponent="3.0"/></feComponentTransfer
></filter><filter x="0" y="0" width="99999" height="99999" id="hc_extension_high
contrast_back"><feComponentTransfer><feFuncR type="gamma" exponent="0.33"/><feFu
ncG type="gamma" exponent="0.33"/><feFuncB type="gamma" exponent="0.33"/></feCom
ponentTransfer></filter><filter x="0" y="0" width="99999" height="99999" id="hc_
extension_grayscale"><feColorMatrix type="matrix" values="0.2126 0.7152 0.0722 0
0 0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0 0 0 0 0 1 0"/><feComponentTra
nsfer><feFuncR type="gamma" exponent="3"/><feFuncG type="gamma" exponent="3"/><f
eFuncB type="gamma" exponent="3"/></feComponentTransfer></filter><filter x="0" y
="0" width="99999" height="99999" id="hc_extension_grayscale_back"><feComponentT
ransfer><feFuncR type="gamma" exponent="0.33"/><feFuncG type="gamma" exponent="0
.33"/><feFuncB type="gamma" exponent="0.33"/></feComponentTransfer></filter><fil
ter x="0" y="0" width="99999" height="99999" id="hc_extension_invert"><feCompone
ntTransfer><feFuncR type="gamma" amplitude="-1" exponent="3" offset="1"/><feFunc
G type="gamma" amplitude="-1" exponent="3" offset="1"/><feFuncB type="gamma" amp
litude="-1" exponent="3" offset="1"/></feComponentTransfer></filter><filter x="0
" y="0" width="99999" height="99999" id="hc_extension_invert_back"><feComponentT
ransfer><feFuncR type="table" tableValues="1 0"/><feFuncG type="table" tableValu
es="1 0"/><feFuncB type="table" tableValues="1 0"/></feComponentTransfer><feComp
onentTransfer><feFuncR type="gamma" exponent="1.7"/><feFuncG type="gamma" expone
nt="1.7"/><feFuncB type="gamma" exponent="1.7"/></feComponentTransfer></filter><
filter x="0" y="0" width="99999" height="99999" id="hc_extension_invert_grayscal
e"><feColorMatrix type="matrix" values="0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0
.0722 0 0 0.2126 0.7152 0.0722 0 0 0 0 0 1 0"/><feComponentTransfer><feFuncR typ
e="gamma" amplitude="-1" exponent="3" offset="1"/><feFuncG type="gamma" amplitud
e="-1" exponent="3" offset="1"/><feFuncB type="gamma" amplitude="-1" exponent="3
" offset="1"/></feComponentTransfer></filter><filter x="0" y="0" width="99999" h
eight="99999" id="hc_extension_yellow_on_black"><feComponentTransfer><feFuncR ty
pe="gamma" amplitude="-1" exponent="3" offset="1"/><feFuncG type="gamma" amplitu
de="-1" exponent="3" offset="1"/><feFuncB type="gamma" amplitude="-1" exponent="
3" offset="1"/></feComponentTransfer><feColorMatrix type="matrix" values="0.3 0.
5 0.2 0 0 0.3 0.5 0.2 0 0 0 0 0 0 0 0 0 0 1 0"/></filter><filter x="0" y="0" wid
th="99999" height="99999" id="hc_extension_yellow_on_black_back"><feComponentTra
nsfer><feFuncR type="table" tableValues="1 0"/><feFuncG type="table" tableValues
="1 0"/><feFuncB type="table" tableValues="1 0"/></feComponentTransfer><feCompon
entTransfer><feFuncR type="gamma" exponent="0.33"/><feFuncG type="gamma" exponen
t="0.33"/><feFuncB type="gamma" exponent="0.33"/></feComponentTransfer></filter>
</defs></svg>'; |
| 20 | 20 |
| 21 function addSvgIfMissing() { | 21 var cssTemplate = 'html[hc="a0"] { -webkit-filter: url("#hc_extension_off"); }
html[hcx="0"] img[src*="jpg"], html[hcx="0"] img[src*="jpeg"], html[hcx="0"] sv
g image, html[hcx="0"] img.rg_i, html[hcx="0"] embed, html[hcx="0"] object, html
[hcx="0"] video { -webkit-filter: url("#hc_extension_off"); } html[hc="a1"] {
-webkit-filter: url("#hc_extension_highcontrast"); } html[hcx="1"] img[src*="
jpg"], html[hcx="1"] img[src*="jpeg"], html[hcx="1"] img.rg_i, html[hcx="1"] svg
image, html[hcx="1"] embed, html[hcx="1"] object, html[hcx="1"] video { -webk
it-filter: url("#hc_extension_highcontrast_back"); } html[hc="a2"] { -webkit-
filter: url("#hc_extension_grayscale"); } html[hcx="2"] img[src*="jpg"], html[hc
x="2"] img[src*="jpeg"], html[hcx="2"] img.rg_i, html[hcx="2"] svg image, html[h
cx="2"] embed, html[hcx="2"] object, html[hcx="2"] video { -webkit-filter: url
("#hc_extension_grayscale_back"); } html[hc="a3"] { -webkit-filter: url("#hc_
extension_invert"); } html[hcx="3"] img[src*="jpg"], html[hcx="3"] img[src*="jpe
g"], html[hcx="3"] img.rg_i, html[hcx="3"] svg image, html[hcx="3"] embed, html[
hcx="3"] object, html[hcx="3"] video { -webkit-filter: url("#hc_extension_inve
rt_back"); } html[hc="a4"] { -webkit-filter: url("#hc_extension_invert_graysc
ale"); } html[hcx="4"] img[src*="jpg"], html[hcx="4"] img[src*="jpeg"], html[hcx
="4"] img.rg_i, html[hcx="4"] svg image, html[hcx="4"] embed, html[hcx="4"] obje
ct, html[hcx="4"] video { -webkit-filter: url("#hc_extension_invert_back"); }
html[hc="a5"] { -webkit-filter: url("#hc_extension_yellow_on_black"); } html[
hcx="5"] img[src*="jpg"], html[hcx="5"] img[src*="jpeg"], html[hcx="5"] img.rg_i
, html[hcx="5"] svg image, html[hcx="5"] embed, html[hcx="5"] object, html[hcx="
5"] video { -webkit-filter: url("#hc_extension_yellow_on_black_back"); }'; |
| 22 |
| 23 /** |
| 24 * Add the elements to the pgae that make high-contrast adjustments possible. |
| 25 */ |
| 26 function addOrUpdateExtraElements() { |
| 27 if (!enabled) |
| 28 return; |
| 29 |
| 30 // We used to include the CSS, but that doesn't work when the document |
| 31 // uses the <base> element to set a relative url. So instead we |
| 32 // add a <style> element directly to the document with the right |
| 33 // urls hard-coded into it. |
| 34 var style = document.getElementById('hc_style'); |
| 35 if (!style) { |
| 36 var baseUrl = window.location.href.replace(window.location.hash, ''); |
| 37 var css = cssTemplate.replace(/#/g, baseUrl + '#'); |
| 38 style = document.createElement('style'); |
| 39 style.id = 'hc_style'; |
| 40 style.setAttribute('type', 'text/css'); |
| 41 style.innerHTML = css; |
| 42 document.head.appendChild(style); |
| 43 } |
| 44 |
| 45 // Starting in Chrome 45 we can't apply a filter to the html element, |
| 46 // so instead we create an element with low z-index that copies the |
| 47 // body's background. |
| 48 var bg = document.getElementById('hc_extension_bkgnd'); |
| 49 if (!bg) { |
| 50 bg = document.createElement('div'); |
| 51 bg.id = 'hc_extension_bkgnd'; |
| 52 bg.style.position = 'fixed'; |
| 53 bg.style.left = '0px'; |
| 54 bg.style.top = '0px'; |
| 55 bg.style.right = '0px'; |
| 56 bg.style.bottom = '0px'; |
| 57 bg.style.zIndex = -1999999999; |
| 58 document.body.appendChild(bg); |
| 59 } |
| 60 bg.style.display = 'block'; |
| 61 bg.style.background = window.getComputedStyle(document.body).background; |
| 62 |
| 63 // As a special case, replace a zero-alpha background with white, |
| 64 // otherwise we can't invert it. |
| 65 var c = bg.style.backgroundColor; |
| 66 c = c.replace(/\s\s*/g,''); |
| 67 if (m = /^rgba\(([\d]+),([\d]+),([\d]+),([\d]+|[\d]*.[\d]+)\)/.exec(c)) { |
| 68 if (m[4] == '0') { |
| 69 bg.style.backgroundColor = '#fff'; |
| 70 } |
| 71 } |
| 72 |
| 73 // Add a hidden element with the SVG filters. |
| 22 var wrap = document.getElementById('hc_extension_svg_filters'); | 74 var wrap = document.getElementById('hc_extension_svg_filters'); |
| 23 if (wrap) | 75 if (wrap) |
| 24 return; | 76 return; |
| 77 |
| 25 wrap = document.createElement('span'); | 78 wrap = document.createElement('span'); |
| 26 wrap.id = 'hc_extension_svg_filters'; | 79 wrap.id = 'hc_extension_svg_filters'; |
| 27 wrap.setAttribute('hidden', ''); | 80 wrap.setAttribute('hidden', ''); |
| 28 wrap.innerHTML = svgContent; | 81 wrap.innerHTML = svgContent; |
| 29 document.body.appendChild(wrap); | 82 document.body.appendChild(wrap); |
| 30 } | 83 } |
| 31 | 84 |
| 85 /** |
| 86 * This is called on load and every time the mode might have changed |
| 87 * (i.e. enabling/disabling, or changing the type of contrast adjustment |
| 88 * for this page). |
| 89 */ |
| 32 function update() { | 90 function update() { |
| 33 var html = document.documentElement; | 91 var html = document.documentElement; |
| 34 if (enabled) { | 92 if (enabled) { |
| 35 if (!document.body) { | 93 if (!document.body) { |
| 36 window.setTimeout(update, 100); | 94 window.setTimeout(update, 100); |
| 37 return; | 95 return; |
| 38 } | 96 } |
| 39 addSvgIfMissing(); | 97 addOrUpdateExtraElements(); |
| 40 if (html.getAttribute('hc') != mode + scheme) | 98 if (html.getAttribute('hc') != mode + scheme) |
| 41 html.setAttribute('hc', mode + scheme); | 99 html.setAttribute('hc', mode + scheme); |
| 42 if (html.getAttribute('hcx') != scheme) | 100 if (html.getAttribute('hcx') != scheme) |
| 43 html.setAttribute('hcx', scheme); | 101 html.setAttribute('hcx', scheme); |
| 44 | 102 |
| 45 if (window == window.top) { | 103 if (window == window.top) { |
| 46 window.scrollBy(0, 1); | 104 window.scrollBy(0, 1); |
| 47 window.scrollBy(0, -1); | 105 window.scrollBy(0, -1); |
| 48 } | 106 } |
| 49 | |
| 50 /** | |
| 51 if (mode == 'a') { | |
| 52 html.style.webkitFilter = filterMap[scheme]; | |
| 53 } | |
| 54 else { | |
| 55 html.style.webkitFilter = 'none'; | |
| 56 }**/ | |
| 57 | |
| 58 } else { | 107 } else { |
| 59 html.setAttribute('hc', mode + '0'); | 108 html.setAttribute('hc', mode + '0'); |
| 60 html.setAttribute('hcx', '0'); | 109 html.setAttribute('hcx', '0'); |
| 61 window.setTimeout(function() { | 110 window.setTimeout(function() { |
| 62 html.removeAttribute('hc'); | 111 html.removeAttribute('hc'); |
| 63 html.removeAttribute('hcx'); | 112 html.removeAttribute('hcx'); |
| 113 var bg = document.getElementById('hc_extension_bkgnd'); |
| 114 if (bg) |
| 115 bg.style.display = 'none'; |
| 64 }, 0); | 116 }, 0); |
| 65 } | 117 } |
| 66 } | 118 } |
| 67 | 119 |
| 120 /** |
| 121 * Called when we get a message from the background page. |
| 122 */ |
| 68 function onExtensionMessage(request) { | 123 function onExtensionMessage(request) { |
| 69 if (enabled != request.enabled || scheme != request.scheme) { | 124 if (enabled != request.enabled || scheme != request.scheme) { |
| 70 enabled = request.enabled; | 125 enabled = request.enabled; |
| 71 scheme = request.scheme; | 126 scheme = request.scheme; |
| 72 update(); | 127 update(); |
| 73 } | 128 } |
| 74 } | 129 } |
| 75 | 130 |
| 76 function onEvent(evt) { | 131 /** |
| 132 * KeyDown event handler |
| 133 */ |
| 134 function onKeyDown(evt) { |
| 77 if (evt.keyCode == 122 /* F11 */ && | 135 if (evt.keyCode == 122 /* F11 */ && |
| 78 evt.shiftKey) { | 136 evt.shiftKey) { |
| 79 chrome.extension.sendRequest({'toggle_global': true}); | 137 chrome.extension.sendRequest({'toggle_global': true}); |
| 80 evt.stopPropagation(); | 138 evt.stopPropagation(); |
| 81 evt.preventDefault(); | 139 evt.preventDefault(); |
| 82 return false; | 140 return false; |
| 83 } | 141 } |
| 84 if (evt.keyCode == 123 /* F12 */ && | 142 if (evt.keyCode == 123 /* F12 */ && |
| 85 evt.shiftKey) { | 143 evt.shiftKey) { |
| 86 chrome.extension.sendRequest({'toggle_site': true}); | 144 chrome.extension.sendRequest({'toggle_site': true}); |
| 87 evt.stopPropagation(); | 145 evt.stopPropagation(); |
| 88 evt.preventDefault(); | 146 evt.preventDefault(); |
| 89 return false; | 147 return false; |
| 90 } | 148 } |
| 91 return true; | 149 return true; |
| 92 } | 150 } |
| 93 | 151 |
| 94 function init() { | 152 function init() { |
| 95 if (window == window.top) { | 153 if (window == window.top) { |
| 96 mode = 'a'; | 154 mode = 'a'; |
| 97 } else { | 155 } else { |
| 98 mode = 'b'; | 156 mode = 'b'; |
| 99 } | 157 } |
| 100 chrome.extension.onRequest.addListener(onExtensionMessage); | 158 chrome.extension.onRequest.addListener(onExtensionMessage); |
| 101 chrome.extension.sendRequest({'init': true}, onExtensionMessage); | 159 chrome.extension.sendRequest({'init': true}, onExtensionMessage); |
| 102 document.addEventListener('keydown', onEvent, false); | 160 document.addEventListener('keydown', onKeyDown, false); |
| 103 | 161 |
| 104 // Work around bug that causes filter to be lost when the HTML element's attri
butes change. | 162 // Update again after a few seconds and again after load so that |
| 105 var html = document.documentElement; | 163 // the background isn't wrong for long. |
| 106 var config = { attributes: true, childList: false, characterData: false }; | 164 window.setTimeout(addOrUpdateExtraElements, 2000); |
| 107 var observer = new MutationObserver(function(mutations) { | 165 window.addEventListener('load', function() { |
| 108 observer.disconnect(); | 166 addOrUpdateExtraElements(); |
| 109 html.removeAttribute('hc'); | 167 |
| 110 html.removeAttribute('hcx'); | 168 // Also update when the document body attributes change. |
| 111 window.setTimeout(function() { | 169 var config = { attributes: true, childList: false, characterData: false }; |
| 112 update(); | 170 var observer = new MutationObserver(function(mutations) { |
| 113 window.setTimeout(function() { | 171 addOrUpdateExtraElements(); |
| 114 observer.observe(html, config); | 172 }); |
| 115 }, 0); | 173 observer.observe(document.body, config); |
| 116 }, 0); | |
| 117 }); | 174 }); |
| 118 observer.observe(html, config); | |
| 119 } | 175 } |
| 120 | 176 |
| 121 init(); | 177 init(); |
| OLD | NEW |