Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: include.preload.js

Issue 29350213: Issue 4364 - Drop support for Chrome 29-40 and remove legacy code (Closed)
Left Patch Set: Created Aug. 25, 2016, 3:09 p.m.
Right Patch Set: Rephrased comment Created Sept. 13, 2016, 3:20 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « composer.postload.js ('k') | metadata.chrome » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2016 Eyeo GmbH 3 * Copyright (C) 2006-2016 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver; 18 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
19 var SELECTOR_GROUP_SIZE = 200;
20 19
21 var typeMap = { 20 var typeMap = {
22 "img": "IMAGE", 21 "img": "IMAGE",
23 "input": "IMAGE", 22 "input": "IMAGE",
24 "picture": "IMAGE", 23 "picture": "IMAGE",
25 "audio": "MEDIA", 24 "audio": "MEDIA",
26 "video": "MEDIA", 25 "video": "MEDIA",
27 "frame": "SUBDOCUMENT", 26 "frame": "SUBDOCUMENT",
28 "iframe": "SUBDOCUMENT", 27 "iframe": "SUBDOCUMENT",
29 "object": "OBJECT", 28 "object": "OBJECT",
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 }, 328 },
330 329
331 disconnect: function() 330 disconnect: function()
332 { 331 {
333 document.removeEventListener("DOMContentLoaded", this.trace); 332 document.removeEventListener("DOMContentLoaded", this.trace);
334 this.observer.disconnect(); 333 this.observer.disconnect();
335 clearTimeout(this.timeout); 334 clearTimeout(this.timeout);
336 } 335 }
337 }; 336 };
338 337
339 function runInDocument(fn, arg) 338 function runInPageContext(fn, arg)
340 { 339 {
341 var script = document.createElement("script"); 340 var script = document.createElement("script");
342 script.type = "application/javascript"; 341 script.type = "application/javascript";
343 script.async = false; 342 script.async = false;
344 script.textContent = "(" + fn + ")(" + JSON.stringify(arg) + ");"; 343 script.textContent = "(" + fn + ")(" + JSON.stringify(arg) + ");";
345 document.documentElement.appendChild(script); 344 document.documentElement.appendChild(script);
346 document.documentElement.removeChild(script); 345 document.documentElement.removeChild(script);
347 } 346 }
348 347
349 // Neither Chrome[1] nor Safari allow us to intercept WebSockets, and therefore 348 // Neither Chrome[1] nor Safari allow us to intercept WebSockets, and therefore
(...skipping 14 matching lines...) Expand all
364 type: "request.websocket", 363 type: "request.websocket",
365 url: event.detail.url 364 url: event.detail.url
366 }, function (block) 365 }, function (block)
367 { 366 {
368 document.dispatchEvent( 367 document.dispatchEvent(
369 new CustomEvent(eventName + "-" + event.detail.url, {detail: block}) 368 new CustomEvent(eventName + "-" + event.detail.url, {detail: block})
370 ); 369 );
371 }); 370 });
372 }); 371 });
373 372
374 runInDocument(function(eventName) 373 runInPageContext(function(eventName)
375 { 374 {
376 // As far as possible we must track everything we use that could be 375 // As far as possible we must track everything we use that could be
377 // sabotaged by the website later in order to circumvent us. 376 // sabotaged by the website later in order to circumvent us.
378 var RealWebSocket = WebSocket; 377 var RealWebSocket = WebSocket;
379 var closeWebSocket = Function.prototype.call.bind(RealWebSocket.prototype.cl ose); 378 var closeWebSocket = Function.prototype.call.bind(RealWebSocket.prototype.cl ose);
380 var addEventListener = document.addEventListener.bind(document); 379 var addEventListener = document.addEventListener.bind(document);
381 var removeEventListener = document.removeEventListener.bind(document); 380 var removeEventListener = document.removeEventListener.bind(document);
382 var dispatchEvent = document.dispatchEvent.bind(document); 381 var dispatchEvent = document.dispatchEvent.bind(document);
383 var CustomEvent = window.CustomEvent; 382 var CustomEvent = window.CustomEvent;
384 383
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 OPEN: {value: RealWebSocket.OPEN, enumerable: true}, 423 OPEN: {value: RealWebSocket.OPEN, enumerable: true},
425 CLOSING: {value: RealWebSocket.CLOSING, enumerable: true}, 424 CLOSING: {value: RealWebSocket.CLOSING, enumerable: true},
426 CLOSED: {value: RealWebSocket.CLOSED, enumerable: true}, 425 CLOSED: {value: RealWebSocket.CLOSED, enumerable: true},
427 prototype: {value: RealWebSocket.prototype} 426 prototype: {value: RealWebSocket.prototype}
428 }); 427 });
429 428
430 RealWebSocket.prototype.constructor = WebSocket; 429 RealWebSocket.prototype.constructor = WebSocket;
431 }, eventName); 430 }, eventName);
432 } 431 }
433 432
434 function init() 433 function ElemHide()
435 { 434 {
436 var shadow = null; 435 this.shadow = this.createShadowTree();
437 var style = null; 436 this.style = null;
438 var observer = null; 437 this.tracer = null;
439 var tracer = null; 438
440 439 this.propertyFilters = new CSSPropertyFilters(
441 wrapWebSocket(); 440 window,
442 441 function(callback)
443 function getPropertyFilters(callback) 442 {
444 { 443 ext.backgroundPage.sendMessage({
445 ext.backgroundPage.sendMessage({ 444 type: "filters.get",
446 type: "filters.get", 445 what: "cssproperties"
447 what: "cssproperties" 446 }, callback);
448 }, callback); 447 },
449 } 448 this.addSelectors.bind(this)
450 var propertyFilters = new CSSPropertyFilters(window, getPropertyFilters, 449 );
451 addElemHideSelectors); 450 }
452 451 ElemHide.prototype = {
453 // Use Shadow DOM if available to don't mess with web pages that rely on 452 selectorGroupSize: 200,
454 // the order of their own <style> tags (#309). 453
455 // 454 createShadowTree: function()
456 // However, creating a shadow root breaks running CSS transitions. So we 455 {
457 // have to create the shadow root before transistions might start (#452). 456 // Use Shadow DOM if available as to not mess with with web pages that
458 // 457 // rely on the order of their own <style> tags (#309). However, creating
459 // Also, using shadow DOM causes issues on some Google websites, 458 // a shadow root breaks running CSS transitions. So we have to create
460 // including Google Docs, Gmail and Blogger (#1770, #2602, #2687). 459 // the shadow root before transistions might start (#452).
461 if ("createShadowRoot" in document.documentElement && 460 if (!("createShadowRoot" in document.documentElement))
462 !/\.(?:google|blogger)\.com$/.test(document.domain)) 461 return null;
463 { 462
464 shadow = document.documentElement.createShadowRoot(); 463 // Using shadow DOM causes issues on some Google websites,
464 // including Google Docs, Gmail and Blogger (#1770, #2602, #2687).
465 if (/\.(?:google|blogger)\.com$/.test(document.domain))
466 return null;
467
468 var shadow = document.documentElement.createShadowRoot();
465 shadow.appendChild(document.createElement("shadow")); 469 shadow.appendChild(document.createElement("shadow"));
466 470
467 // Stop the website from messing with our shadowRoot 471 // Stop the website from messing with our shadow root (#4191, #4298).
468 if ("shadowRoot" in Element.prototype) 472 if ("shadowRoot" in Element.prototype)
469 { 473 {
470 runInDocument(function() 474 runInPageContext(function()
471 { 475 {
472 var ourShadowRoot = document.documentElement.shadowRoot; 476 var ourShadowRoot = document.documentElement.shadowRoot;
473 var desc = Object.getOwnPropertyDescriptor(Element.prototype, "shadowRoo t"); 477 var desc = Object.getOwnPropertyDescriptor(Element.prototype, "shadowRoo t");
474 var shadowRoot = Function.prototype.call.bind(desc.get); 478 var shadowRoot = Function.prototype.call.bind(desc.get);
475 479
476 Object.defineProperty(Element.prototype, "shadowRoot", { 480 Object.defineProperty(Element.prototype, "shadowRoot", {
477 configurable: true, enumerable: true, get: function() 481 configurable: true, enumerable: true, get: function()
478 { 482 {
479 var shadow = shadowRoot(this); 483 var shadow = shadowRoot(this);
480 return shadow == ourShadowRoot ? null : shadow; 484 return shadow == ourShadowRoot ? null : shadow;
481 } 485 }
482 }); 486 });
483 }, null); 487 }, null);
484 } 488 }
485 } 489
486 490 return shadow;
487 function addElemHideSelectors(selectors) 491 },
492
493 addSelectors: function(selectors)
488 { 494 {
489 if (selectors.length == 0) 495 if (selectors.length == 0)
490 return; 496 return;
491 497
492 if (!style) 498 if (!this.style)
493 { 499 {
494 // Create <style> element lazily, only if we add styles. Add it to 500 // Create <style> element lazily, only if we add styles. Add it to
495 // the shadow DOM if possible. Otherwise fallback to the <head> or 501 // the shadow DOM if possible. Otherwise fallback to the <head> or
496 // <html> element. If we have injected a style element before that 502 // <html> element. If we have injected a style element before that
497 // has been removed (the sheet property is null), create a new one. 503 // has been removed (the sheet property is null), create a new one.
498 style = document.createElement("style"); 504 this.style = document.createElement("style");
499 (shadow || document.head || document.documentElement).appendChild(style); 505 (this.shadow || document.head
506 || document.documentElement).appendChild(this.style);
500 507
501 // It can happen that the frame already navigated to a different 508 // It can happen that the frame already navigated to a different
502 // document while we were waiting for the background page to respond. 509 // document while we were waiting for the background page to respond.
503 // In that case the sheet property will stay null, after addind the 510 // In that case the sheet property will stay null, after addind the
504 // <style> element to the shadow DOM. 511 // <style> element to the shadow DOM.
505 if (!style.sheet) 512 if (!this.style.sheet)
506 return; 513 return;
507 } 514 }
508 515
509 // If using shadow DOM, we have to add the ::content pseudo-element 516 // If using shadow DOM, we have to add the ::content pseudo-element
510 // before each selector, in order to match elements within the 517 // before each selector, in order to match elements within the
511 // insertion point. 518 // insertion point.
512 if (shadow) 519 if (this.shadow)
513 { 520 {
514 var preparedSelectors = []; 521 var preparedSelectors = [];
515 for (var i = 0; i < selectors.length; i++) 522 for (var i = 0; i < selectors.length; i++)
516 { 523 {
517 var subSelectors = splitSelector(selectors[i]); 524 var subSelectors = splitSelector(selectors[i]);
518 for (var j = 0; j < subSelectors.length; j++) 525 for (var j = 0; j < subSelectors.length; j++)
519 preparedSelectors.push("::content " + subSelectors[j]); 526 preparedSelectors.push("::content " + subSelectors[j]);
520 } 527 }
521 selectors = preparedSelectors; 528 selectors = preparedSelectors;
522 } 529 }
523 530
524 // Safari only allows 8192 primitive selectors to be injected at once[1], we 531 // Safari only allows 8192 primitive selectors to be injected at once[1], we
525 // therefore chunk the inserted selectors into groups of 200 to be safe. 532 // therefore chunk the inserted selectors into groups of 200 to be safe.
526 // (Chrome also has a limit, larger... but we're not certain exactly what it 533 // (Chrome also has a limit, larger... but we're not certain exactly what it
527 // is! Edge apparently has no such limit.) 534 // is! Edge apparently has no such limit.)
528 // [1] - https://github.com/WebKit/webkit/blob/1cb2227f6b2a1035f7bdc46e5ab69 debb75fc1de/Source/WebCore/css/RuleSet.h#L68 535 // [1] - https://github.com/WebKit/webkit/blob/1cb2227f6b2a1035f7bdc46e5ab69 debb75fc1de/Source/WebCore/css/RuleSet.h#L68
529 for (var i = 0; i < selectors.length; i += SELECTOR_GROUP_SIZE) 536 for (var i = 0; i < selectors.length; i += this.selectorGroupSize)
530 { 537 {
531 var selector = selectors.slice(i, i + SELECTOR_GROUP_SIZE).join(", "); 538 var selector = selectors.slice(i, i + this.selectorGroupSize).join(", ");
532 style.sheet.addRule(selector, "display: none !important;"); 539 this.style.sheet.addRule(selector, "display: none !important;");
533 } 540 }
534 }; 541 },
535 542
536 var updateStylesheet = function() 543 apply: function()
537 { 544 {
538 var selectors = null; 545 var selectors = null;
539 var CSSPropertyFiltersLoaded = false; 546 var propertyFiltersLoaded = false;
540 547
541 var checkLoaded = function() 548 var checkLoaded = function()
542 { 549 {
543 if (!selectors || !CSSPropertyFiltersLoaded) 550 if (!selectors || !propertyFiltersLoaded)
544 return; 551 return;
545 552
546 if (observer) 553 if (this.tracer)
547 observer.disconnect(); 554 this.tracer.disconnect();
548 observer = null; 555 this.tracer = null;
549 556
550 if (tracer) 557 if (this.style && this.style.parentElement)
551 tracer.disconnect(); 558 this.style.parentElement.removeChild(this.style);
552 tracer = null; 559 this.style = null;
553 560
554 if (style && style.parentElement) 561 this.addSelectors(selectors.selectors);
555 style.parentElement.removeChild(style); 562 this.propertyFilters.apply();
556 style = null;
557
558 addElemHideSelectors(selectors.selectors);
559 propertyFilters.apply();
560 563
561 if (selectors.trace) 564 if (selectors.trace)
562 tracer = new ElementHidingTracer(selectors.selectors); 565 this.tracer = new ElementHidingTracer(selectors.selectors);
563 }; 566 }.bind(this);
564 567
565 ext.backgroundPage.sendMessage({type: "get-selectors"}, function(response) 568 ext.backgroundPage.sendMessage({type: "get-selectors"}, function(response)
566 { 569 {
567 selectors = response; 570 selectors = response;
568 checkLoaded(); 571 checkLoaded();
569 }); 572 });
570 573
571 propertyFilters.load(function() 574 this.propertyFilters.load(function()
572 { 575 {
573 CSSPropertyFiltersLoaded = true; 576 propertyFiltersLoaded = true;
574 checkLoaded(); 577 checkLoaded();
575 }); 578 });
576 }; 579 }
577 580 };
578 updateStylesheet(); 581
582 if (document instanceof HTMLDocument)
583 {
584 checkSitekey();
585 wrapWebSocket();
586
587 var elemhide = new ElemHide();
588 elemhide.apply();
579 589
580 document.addEventListener("error", function(event) 590 document.addEventListener("error", function(event)
581 { 591 {
582 checkCollapse(event.target); 592 checkCollapse(event.target);
583 }, true); 593 }, true);
584 594
585 document.addEventListener("load", function(event) 595 document.addEventListener("load", function(event)
586 { 596 {
587 var element = event.target; 597 var element = event.target;
588 if (/^i?frame$/.test(element.localName)) 598 if (/^i?frame$/.test(element.localName))
589 checkCollapse(element); 599 checkCollapse(element);
590 }, true); 600 }, true);
591 601 }
592 return updateStylesheet;
593 }
594
595 if (document instanceof HTMLDocument)
596 {
597 checkSitekey();
598 window.updateStylesheet = init();
599 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld