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 sip
from PyQt5.QtGui import QFont
from PyQt5.QtWebEngineWidgets import (QWebEngineSettings, QWebEngineProfile,
QWebEngineScript)
@ -37,7 +38,7 @@ from qutebrowser.browser import shared
from qutebrowser.browser.webengine import spell
from qutebrowser.config import config, websettings
from qutebrowser.utils import (utils, standarddir, javascript, qtutils,
message, log)
message, log, objreg)
# The default QWebEngineProfile
default_profile = None
@ -153,33 +154,44 @@ class DictionaryLanguageSetter(DefaultProfileSetter):
def _init_stylesheet(profile):
"""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/tools/scripts.cpp#L119-L132
"""
old_script = profile.scripts().findScript('_qute_stylesheet')
if not old_script.isNull():
profile.scripts().remove(old_script)
css = shared.get_user_stylesheet()
source = """
(function() {{
var css = document.createElement('style');
css.setAttribute('type', 'text/css');
css.appendChild(document.createTextNode('{}'));
document.getElementsByTagName('head')[0].appendChild(css);
}})()
""".format(javascript.string_escape(css))
source = '\n'.join([
'"use strict";',
'window._qutebrowser = window._qutebrowser || {};',
utils.read_file('javascript/stylesheet.js'),
javascript.assemble('stylesheet', 'set_css', css),
])
script = QWebEngineScript()
script.setName('_qute_stylesheet')
script.setInjectionPoint(QWebEngineScript.DocumentReady)
script.setInjectionPoint(QWebEngineScript.DocumentCreation)
script.setWorldId(QWebEngineScript.ApplicationWorld)
script.setRunsOnSubFrames(True)
script.setSourceCode(source)
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):
"""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']:
_init_stylesheet(default_profile)
_init_stylesheet(private_profile)
_update_stylesheet()
elif option in ['content.headers.user_agent',
'content.headers.accept_language']:
_set_http_headers(default_profile)

View File

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

View File

@ -41,3 +41,4 @@ rules:
no-multi-spaces: ["error", {"ignoreEOLComments": true}]
function-paren-newline: "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">
=20
<title>Simple MHTML test</title>
<style type=3D"text/css">
html > ::-webkit-scrollbar { width: 0px; height: 0px; }</style></head>
</head>
<body>
<a href=3D"http://localhost:(port)/">normal link to another page</a>
=20
</body></html>
</body><style>
html > ::-webkit-scrollbar { width: 0px; height: 0px; }</style></html>
-----=_qute-UUID