Merge remote-tracking branch 'origin/pr/3212'

This commit is contained in:
Florian Bruhin 2017-11-19 14:24:40 +01:00
commit 91c909cb80
5 changed files with 166 additions and 16 deletions

View File

@ -29,6 +29,7 @@ Module attributes:
import os import os
import sip
from PyQt5.QtGui import QFont from PyQt5.QtGui import QFont
from PyQt5.QtWebEngineWidgets import (QWebEngineSettings, QWebEngineProfile, from PyQt5.QtWebEngineWidgets import (QWebEngineSettings, QWebEngineProfile,
QWebEngineScript) QWebEngineScript)
@ -37,7 +38,7 @@ from qutebrowser.browser import shared
from qutebrowser.browser.webengine import spell from qutebrowser.browser.webengine import spell
from qutebrowser.config import config, websettings from qutebrowser.config import config, websettings
from qutebrowser.utils import (utils, standarddir, javascript, qtutils, from qutebrowser.utils import (utils, standarddir, javascript, qtutils,
message, log) message, log, objreg)
# The default QWebEngineProfile # The default QWebEngineProfile
default_profile = None default_profile = None
@ -153,33 +154,44 @@ class DictionaryLanguageSetter(DefaultProfileSetter):
def _init_stylesheet(profile): def _init_stylesheet(profile):
"""Initialize custom stylesheets. """Initialize custom stylesheets.
Mostly inspired by QupZilla: Partially inspired by QupZilla:
https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/app/mainapplication.cpp#L1063-L1101 https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/app/mainapplication.cpp#L1063-L1101
https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/tools/scripts.cpp#L119-L132
""" """
old_script = profile.scripts().findScript('_qute_stylesheet') old_script = profile.scripts().findScript('_qute_stylesheet')
if not old_script.isNull(): if not old_script.isNull():
profile.scripts().remove(old_script) profile.scripts().remove(old_script)
css = shared.get_user_stylesheet() css = shared.get_user_stylesheet()
source = """ source = '\n'.join([
(function() {{ '"use strict";',
var css = document.createElement('style'); 'window._qutebrowser = window._qutebrowser || {};',
css.setAttribute('type', 'text/css'); utils.read_file('javascript/stylesheet.js'),
css.appendChild(document.createTextNode('{}')); javascript.assemble('stylesheet', 'set_css', css),
document.getElementsByTagName('head')[0].appendChild(css); ])
}})()
""".format(javascript.string_escape(css))
script = QWebEngineScript() script = QWebEngineScript()
script.setName('_qute_stylesheet') script.setName('_qute_stylesheet')
script.setInjectionPoint(QWebEngineScript.DocumentReady) script.setInjectionPoint(QWebEngineScript.DocumentCreation)
script.setWorldId(QWebEngineScript.ApplicationWorld) script.setWorldId(QWebEngineScript.ApplicationWorld)
script.setRunsOnSubFrames(True) script.setRunsOnSubFrames(True)
script.setSourceCode(source) script.setSourceCode(source)
profile.scripts().insert(script) profile.scripts().insert(script)
def _update_stylesheet():
"""Update the custom stylesheet in existing tabs."""
css = shared.get_user_stylesheet()
code = javascript.assemble('stylesheet', 'set_css', css)
for win_id, window in objreg.window_registry.items():
# We could be in the middle of destroying a window here
if sip.isdeleted(window):
continue
tab_registry = objreg.get('tab-registry', scope='window',
window=win_id)
for tab in tab_registry.values():
tab.run_js_async(code)
def _set_http_headers(profile): def _set_http_headers(profile):
"""Set the user agent and accept-language for the given profile. """Set the user agent and accept-language for the given profile.
@ -199,6 +211,7 @@ def _update_settings(option):
if option in ['scrolling.bar', 'content.user_stylesheets']: if option in ['scrolling.bar', 'content.user_stylesheets']:
_init_stylesheet(default_profile) _init_stylesheet(default_profile)
_init_stylesheet(private_profile) _init_stylesheet(private_profile)
_update_stylesheet()
elif option in ['content.headers.user_agent', elif option in ['content.headers.user_agent',
'content.headers.accept_language']: 'content.headers.accept_language']:
_set_http_headers(default_profile) _set_http_headers(default_profile)

View File

@ -544,7 +544,7 @@ class WebEngineTab(browsertab.AbstractTab):
def _init_js(self): def _init_js(self):
js_code = '\n'.join([ js_code = '\n'.join([
'"use strict";', '"use strict";',
'window._qutebrowser = {};', 'window._qutebrowser = window._qutebrowser || {};',
utils.read_file('javascript/scroll.js'), utils.read_file('javascript/scroll.js'),
utils.read_file('javascript/webelem.js'), utils.read_file('javascript/webelem.js'),
]) ])

View File

@ -41,3 +41,4 @@ rules:
no-multi-spaces: ["error", {"ignoreEOLComments": true}] no-multi-spaces: ["error", {"ignoreEOLComments": true}]
function-paren-newline: "off" function-paren-newline: "off"
multiline-comment-style: "off" multiline-comment-style: "off"
no-bitwise: "off"

View File

@ -0,0 +1,136 @@
/**
* Copyright 2017 Ulrik de Muelenaere <ulrikdem@gmail.com>
*
* This file is part of qutebrowser.
*
* qutebrowser is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* qutebrowser is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
*/
"use strict";
window._qutebrowser.stylesheet = (function() {
if (window._qutebrowser.stylesheet) {
return window._qutebrowser.stylesheet;
}
const funcs = {};
const xhtml_ns = "http://www.w3.org/1999/xhtml";
const svg_ns = "http://www.w3.org/2000/svg";
let root_elem;
let style_elem;
let css_content = "";
let root_observer;
let initialized = false;
// Watch for rewrites of the root element and changes to its children,
// then move the stylesheet to the end. Partially inspired by Stylus:
// https://github.com/openstyles/stylus/blob/1.1.4.2/content/apply.js#L235-L355
function watch_root() {
if (root_elem !== document.documentElement) {
root_elem = document.documentElement;
root_observer.disconnect();
root_observer.observe(document, {"childList": true});
root_observer.observe(root_elem, {"childList": true});
}
if (style_elem !== root_elem.lastChild) {
root_elem.appendChild(style_elem);
}
}
function create_style() {
let ns = xhtml_ns;
if (document.documentElement.namespaceURI === svg_ns) {
ns = svg_ns;
}
style_elem = document.createElementNS(ns, "style");
style_elem.textContent = css_content;
root_observer = new MutationObserver(watch_root);
watch_root();
}
// We should only inject the stylesheet if the document already has style
// information associated with it. Otherwise we wait until the browser
// rewrites it to an XHTML document showing the document tree. As a
// starting point for exploring the relevant code in Chromium, see
// https://github.com/qt/qtwebengine-chromium/blob/cfe8c60/chromium/third_party/WebKit/Source/core/xml/parser/XMLDocumentParser.cpp#L1539-L1540
function check_style(node) {
const stylesheet = node.nodeType === Node.PROCESSING_INSTRUCTION_NODE &&
node.target === "xml-stylesheet" &&
node.parentNode === document;
const known_ns = node.nodeType === Node.ELEMENT_NODE &&
(node.namespaceURI === xhtml_ns ||
node.namespaceURI === svg_ns);
return stylesheet || known_ns;
}
function init() {
initialized = true;
// Chromium will not rewrite a document inside a frame, so add the
// stylesheet even if the document is unstyled.
if (window !== window.top) {
create_style();
return;
}
const iter = document.createNodeIterator(document,
NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_ELEMENT);
let node;
while ((node = iter.nextNode())) {
if (check_style(node)) {
create_style();
return;
}
}
const style_observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
const nodes = mutation.addedNodes;
for (let i = 0; i < nodes.length; ++i) {
if (check_style(nodes[i])) {
create_style();
style_observer.disconnect();
return;
}
}
}
});
style_observer.observe(document, {"childList": true, "subtree": true});
}
funcs.set_css = function(css) {
if (!initialized) {
init();
}
if (style_elem) {
style_elem.textContent = css;
// The browser seems to rewrite the document in same-origin frames
// without notifying the mutation observer. Ensure that the
// stylesheet is in the current document.
watch_root();
} else {
css_content = css;
}
// Propagate the new CSS to all child frames.
// FIXME:qtwebengine This does not work for cross-origin frames.
for (let i = 0; i < window.frames.length; ++i) {
const frame = window.frames[i];
if (frame._qutebrowser && frame._qutebrowser.stylesheet) {
frame._qutebrowser.stylesheet.set_css(css);
}
}
};
return funcs;
})();

View File

@ -16,11 +16,11 @@ Content-Location: http://localhost:(port)/data/downloads/mhtml/simple/simple.htm
t/html; charset=3DUTF-8"> t/html; charset=3DUTF-8">
=20 =20
<title>Simple MHTML test</title> <title>Simple MHTML test</title>
<style type=3D"text/css"> </head>
html > ::-webkit-scrollbar { width: 0px; height: 0px; }</style></head>
<body> <body>
<a href=3D"http://localhost:(port)/">normal link to another page</a> <a href=3D"http://localhost:(port)/">normal link to another page</a>
=20 =20
</body></html> </body><style>
html > ::-webkit-scrollbar { width: 0px; height: 0px; }</style></html>
-----=_qute-UUID -----=_qute-UUID