diff --git a/extensions/chromium/contentscript.js b/extensions/chromium/contentscript.js index 699e3d2f1..531e0f7c1 100644 --- a/extensions/chromium/contentscript.js +++ b/extensions/chromium/contentscript.js @@ -25,15 +25,108 @@ function getViewerURL(pdf_url) { return VIEWER_URL + '?file=' + encodeURIComponent(pdf_url); } -document.addEventListener('beforeload', function(event) { - var elem = event.target; - if (elem.nodeName.toUpperCase() !== 'EMBED') { +// (un)prefixed property names +var createShadowRoot, shadowRoot; +if (typeof Element.prototype.createShadowRoot !== 'undefined') { + // Chrome 35+ + createShadowRoot = 'createShadowRoot'; + shadowRoot = 'shadowRoot'; +} else if (typeof Element.prototype.webkitCreateShadowRoot !== 'undefined') { + // Chrome 25 - 34 + createShadowRoot = 'webkitCreateShadowRoot'; + shadowRoot = 'webkitShadowRoot'; + try { + document.createElement('embed').webkitCreateShadowRoot(); + } catch (e) { + // Only supported since Chrome 33. + createShadowRoot = shadowRoot = ''; + } +} + +// Only observe the document if we can make use of Shadow DOM. +if (createShadowRoot) { + if ('animation' in document.documentElement.style) { + document.addEventListener('animationstart', onAnimationStart, true); + } else { + document.addEventListener('webkitAnimationStart', onAnimationStart, true); + } +} + +function onAnimationStart(event) { + if (event.animationName === 'pdfjs-detected-object-or-embed') { + watchObjectOrEmbed(event.target); + } +} + +// Called for every or element in the page. +// It does not trigger any Mutation observers, but it may modify the +// shadow DOM rooted under the given element. +// Calling this function multiple times for the same element is safe, i.e. +// it has no side effects. +function watchObjectOrEmbed(elem) { + var mimeType = elem.type; + if (mimeType && 'application/pdf' !== mimeType.toLowerCase()) { return; } - if (!/^application\/pdf$/i.test(elem.type)) { + // + var srcAttribute = 'src' in elem ? 'src' : 'data'; + var path = elem[srcAttribute]; + if (!mimeType && !/\.pdf($|[?#])/i.test(path)) { return; } - event.preventDefault(); - elem.type = 'text/html'; - elem.src = getViewerURL(elem.src); -}, true); + + if (elem[shadowRoot]) { + // If the element already has a shadow root, assume that we've already + // seen this element. + return; + } + elem[createShadowRoot](); + + function updateViewerFrame() { + var path = elem[srcAttribute]; + if (!path) { + elem[shadowRoot].textContent = ''; + } else { + elem[shadowRoot].innerHTML = + // Set display: inline-block; to the host element (/) to + // ensure that the dimensions defined on the host element are applied to + // the iframe (http://crbug.com/358648). + // The styles are declared in the shadow DOM to allow page authors to + // override these styles (e.g. .style.display = 'none';). + '' + + ''; + elem[shadowRoot].lastChild.src = getEmbeddedViewerURL(path); + } + } + + updateViewerFrame(); + + // Watch for page-initiated changes of the src/data attribute. + var srcObserver = new MutationObserver(updateViewerFrame); + srcObserver.observe(elem, { + attributes: true, + childList: false, + characterData: false, + attributeFilter: [srcAttribute] + }); +} + +// Get the viewer URL, provided that the path is a valid URL. +function getEmbeddedViewerURL(path) { + var fragment = /^([^#]*)(#.*)?$/.exec(path); + path = fragment[1]; + fragment = fragment[2] || ''; + + // Resolve relative path to document. + var a = document.createElement('a'); + a.href = document.baseURI; + a.href = path; + path = a.href; + return getViewerURL(path) + fragment; +} diff --git a/extensions/chromium/contentstyle.css b/extensions/chromium/contentstyle.css new file mode 100644 index 000000000..1277bb550 --- /dev/null +++ b/extensions/chromium/contentstyle.css @@ -0,0 +1,13 @@ +/** + * Detect creation of and tags. + */ +@-webkit-keyframes pdfjs-detected-object-or-embed { from {} } +@keyframes pdfjs-detected-object-or-embed { from {} } +object, embed { + -webkit-animation-delay: 0s !important; + -webkit-animation-name: pdfjs-detected-object-or-embed !important; + -webkit-animation-play-state: running !important; + animation-delay: 0s !important; + animation-name: pdfjs-detected-object-or-embed !important; + animation-play-state: running !important; +} diff --git a/extensions/chromium/manifest.json b/extensions/chromium/manifest.json index 5ae4e3fde..214787f30 100644 --- a/extensions/chromium/manifest.json +++ b/extensions/chromium/manifest.json @@ -25,6 +25,8 @@ "file://*/*" ], "run_at": "document_start", + "all_frames": true, + "css": ["contentstyle.css"], "js": ["contentscript.js"] }], "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",