|
|
|
|
@@ -44,15 +44,16 @@ import {
|
|
|
|
|
fontParam,
|
|
|
|
|
Mirror,
|
|
|
|
|
styleDeclarationCallback,
|
|
|
|
|
IWindow,
|
|
|
|
|
} from '../types';
|
|
|
|
|
import MutationBuffer from './mutation';
|
|
|
|
|
import { IframeManager } from './iframe-manager';
|
|
|
|
|
import { ShadowDomManager } from './shadow-dom-manager';
|
|
|
|
|
|
|
|
|
|
type WindowWithStoredMutationObserver = Window & {
|
|
|
|
|
type WindowWithStoredMutationObserver = IWindow & {
|
|
|
|
|
__rrMutationObserver?: MutationObserver;
|
|
|
|
|
};
|
|
|
|
|
type WindowWithAngularZone = Window & {
|
|
|
|
|
type WindowWithAngularZone = IWindow & {
|
|
|
|
|
Zone?: {
|
|
|
|
|
__symbol__?: (key: string) => string;
|
|
|
|
|
};
|
|
|
|
|
@@ -519,11 +520,14 @@ function getNestedCSSRulePositions(rule: CSSRule): number[] {
|
|
|
|
|
|
|
|
|
|
function initStyleSheetObserver(
|
|
|
|
|
cb: styleSheetRuleCallback,
|
|
|
|
|
win: Window,
|
|
|
|
|
win: IWindow,
|
|
|
|
|
mirror: Mirror,
|
|
|
|
|
): listenerHandler {
|
|
|
|
|
const insertRule = (win as any).CSSStyleSheet.prototype.insertRule;
|
|
|
|
|
(win as any).CSSStyleSheet.prototype.insertRule = function (rule: string, index?: number) {
|
|
|
|
|
const insertRule = win.CSSStyleSheet.prototype.insertRule;
|
|
|
|
|
win.CSSStyleSheet.prototype.insertRule = function (
|
|
|
|
|
rule: string,
|
|
|
|
|
index?: number,
|
|
|
|
|
) {
|
|
|
|
|
const id = mirror.getId(this.ownerNode as INode);
|
|
|
|
|
if (id !== -1) {
|
|
|
|
|
cb({
|
|
|
|
|
@@ -534,8 +538,8 @@ function initStyleSheetObserver(
|
|
|
|
|
return insertRule.apply(this, arguments);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const deleteRule = (win as any).CSSStyleSheet.prototype.deleteRule;
|
|
|
|
|
(win as any).CSSStyleSheet.prototype.deleteRule = function (index: number) {
|
|
|
|
|
const deleteRule = win.CSSStyleSheet.prototype.deleteRule;
|
|
|
|
|
win.CSSStyleSheet.prototype.deleteRule = function (index: number) {
|
|
|
|
|
const id = mirror.getId(this.ownerNode as INode);
|
|
|
|
|
if (id !== -1) {
|
|
|
|
|
cb({
|
|
|
|
|
@@ -550,20 +554,20 @@ function initStyleSheetObserver(
|
|
|
|
|
[key: string]: GroupingCSSRuleTypes;
|
|
|
|
|
} = {};
|
|
|
|
|
if (isCSSGroupingRuleSupported) {
|
|
|
|
|
supportedNestedCSSRuleTypes['CSSGroupingRule'] = (win as any).CSSGroupingRule;
|
|
|
|
|
supportedNestedCSSRuleTypes.CSSGroupingRule = win.CSSGroupingRule;
|
|
|
|
|
} else {
|
|
|
|
|
// Some browsers (Safari) don't support CSSGroupingRule
|
|
|
|
|
// https://caniuse.com/?search=cssgroupingrule
|
|
|
|
|
// fall back to monkey patching classes that would have inherited from CSSGroupingRule
|
|
|
|
|
|
|
|
|
|
if (isCSSMediaRuleSupported) {
|
|
|
|
|
supportedNestedCSSRuleTypes['CSSMediaRule'] = (win as any).CSSMediaRule;
|
|
|
|
|
supportedNestedCSSRuleTypes.CSSMediaRule = win.CSSMediaRule;
|
|
|
|
|
}
|
|
|
|
|
if (isCSSConditionRuleSupported) {
|
|
|
|
|
supportedNestedCSSRuleTypes['CSSConditionRule'] = (win as any).CSSConditionRule;
|
|
|
|
|
supportedNestedCSSRuleTypes.CSSConditionRule = win.CSSConditionRule;
|
|
|
|
|
}
|
|
|
|
|
if (isCSSSupportsRuleSupported) {
|
|
|
|
|
supportedNestedCSSRuleTypes['CSSSupportsRule'] = (win as any).CSSSupportsRule;
|
|
|
|
|
supportedNestedCSSRuleTypes.CSSSupportsRule = win.CSSSupportsRule;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -612,8 +616,8 @@ function initStyleSheetObserver(
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
(win as any).CSSStyleSheet.prototype.insertRule = insertRule;
|
|
|
|
|
(win as any).CSSStyleSheet.prototype.deleteRule = deleteRule;
|
|
|
|
|
win.CSSStyleSheet.prototype.insertRule = insertRule;
|
|
|
|
|
win.CSSStyleSheet.prototype.deleteRule = deleteRule;
|
|
|
|
|
Object.entries(supportedNestedCSSRuleTypes).forEach(([typeKey, type]) => {
|
|
|
|
|
type.prototype.insertRule = unmodifiedFunctions[typeKey].insertRule;
|
|
|
|
|
type.prototype.deleteRule = unmodifiedFunctions[typeKey].deleteRule;
|
|
|
|
|
@@ -623,11 +627,11 @@ function initStyleSheetObserver(
|
|
|
|
|
|
|
|
|
|
function initStyleDeclarationObserver(
|
|
|
|
|
cb: styleDeclarationCallback,
|
|
|
|
|
win: Window,
|
|
|
|
|
win: IWindow,
|
|
|
|
|
mirror: Mirror,
|
|
|
|
|
): listenerHandler {
|
|
|
|
|
const setProperty = (win as any).CSSStyleDeclaration.prototype.setProperty;
|
|
|
|
|
(win as any).CSSStyleDeclaration.prototype.setProperty = function (
|
|
|
|
|
const setProperty = win.CSSStyleDeclaration.prototype.setProperty;
|
|
|
|
|
win.CSSStyleDeclaration.prototype.setProperty = function (
|
|
|
|
|
this: CSSStyleDeclaration,
|
|
|
|
|
property: string,
|
|
|
|
|
value: string,
|
|
|
|
|
@@ -650,8 +654,8 @@ function initStyleDeclarationObserver(
|
|
|
|
|
return setProperty.apply(this, arguments);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const removeProperty = (win as any).CSSStyleDeclaration.prototype.removeProperty;
|
|
|
|
|
(win as any).CSSStyleDeclaration.prototype.removeProperty = function (
|
|
|
|
|
const removeProperty = win.CSSStyleDeclaration.prototype.removeProperty;
|
|
|
|
|
win.CSSStyleDeclaration.prototype.removeProperty = function (
|
|
|
|
|
this: CSSStyleDeclaration,
|
|
|
|
|
property: string,
|
|
|
|
|
) {
|
|
|
|
|
@@ -671,8 +675,8 @@ function initStyleDeclarationObserver(
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
(win as any).CSSStyleDeclaration.prototype.setProperty = setProperty;
|
|
|
|
|
(win as any).CSSStyleDeclaration.prototype.removeProperty = removeProperty;
|
|
|
|
|
win.CSSStyleDeclaration.prototype.setProperty = setProperty;
|
|
|
|
|
win.CSSStyleDeclaration.prototype.removeProperty = removeProperty;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -704,23 +708,25 @@ function initMediaInteractionObserver(
|
|
|
|
|
|
|
|
|
|
function initCanvasMutationObserver(
|
|
|
|
|
cb: canvasMutationCallback,
|
|
|
|
|
win: Window,
|
|
|
|
|
win: IWindow,
|
|
|
|
|
blockClass: blockClass,
|
|
|
|
|
mirror: Mirror,
|
|
|
|
|
): listenerHandler {
|
|
|
|
|
const props = Object.getOwnPropertyNames((win as any).CanvasRenderingContext2D.prototype);
|
|
|
|
|
const props = Object.getOwnPropertyNames(
|
|
|
|
|
win.CanvasRenderingContext2D.prototype,
|
|
|
|
|
);
|
|
|
|
|
const handlers: listenerHandler[] = [];
|
|
|
|
|
for (const prop of props) {
|
|
|
|
|
try {
|
|
|
|
|
if (
|
|
|
|
|
typeof (win as any).CanvasRenderingContext2D.prototype[
|
|
|
|
|
typeof win.CanvasRenderingContext2D.prototype[
|
|
|
|
|
prop as keyof CanvasRenderingContext2D
|
|
|
|
|
] !== 'function'
|
|
|
|
|
) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const restoreHandler = patch(
|
|
|
|
|
(win as any).CanvasRenderingContext2D.prototype,
|
|
|
|
|
win.CanvasRenderingContext2D.prototype,
|
|
|
|
|
prop,
|
|
|
|
|
function (original) {
|
|
|
|
|
return function (
|
|
|
|
|
@@ -761,7 +767,7 @@ function initCanvasMutationObserver(
|
|
|
|
|
handlers.push(restoreHandler);
|
|
|
|
|
} catch {
|
|
|
|
|
const hookHandler = hookSetter<CanvasRenderingContext2D>(
|
|
|
|
|
(win as any).CanvasRenderingContext2D.prototype,
|
|
|
|
|
win.CanvasRenderingContext2D.prototype,
|
|
|
|
|
prop,
|
|
|
|
|
{
|
|
|
|
|
set(v) {
|
|
|
|
|
@@ -782,19 +788,18 @@ function initCanvasMutationObserver(
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function initFontObserver(
|
|
|
|
|
cb: fontCallback,
|
|
|
|
|
doc: Document,
|
|
|
|
|
): listenerHandler {
|
|
|
|
|
const win = doc.defaultView;
|
|
|
|
|
function initFontObserver(cb: fontCallback, doc: Document): listenerHandler {
|
|
|
|
|
const win = doc.defaultView as IWindow;
|
|
|
|
|
if (!win) {
|
|
|
|
|
return () => {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handlers: listenerHandler[] = [];
|
|
|
|
|
|
|
|
|
|
const fontMap = new WeakMap<FontFace, fontParam>();
|
|
|
|
|
|
|
|
|
|
const originalFontFace = (win as any).FontFace;
|
|
|
|
|
// tslint:disable-next-line: no-any
|
|
|
|
|
(win as any).FontFace = function FontFace(
|
|
|
|
|
const originalFontFace = win.FontFace;
|
|
|
|
|
win.FontFace = (function FontFace(
|
|
|
|
|
family: string,
|
|
|
|
|
source: string | ArrayBufferView,
|
|
|
|
|
descriptors?: FontFaceDescriptors,
|
|
|
|
|
@@ -811,7 +816,7 @@ function initFontObserver(
|
|
|
|
|
JSON.stringify(Array.from(new Uint8Array(source as any))),
|
|
|
|
|
});
|
|
|
|
|
return fontFace;
|
|
|
|
|
};
|
|
|
|
|
} as unknown) as typeof FontFace;
|
|
|
|
|
|
|
|
|
|
const restoreHandler = patch(doc.fonts, 'add', function (original) {
|
|
|
|
|
return function (this: FontFaceSet, fontFace: FontFace) {
|
|
|
|
|
@@ -827,8 +832,7 @@ function initFontObserver(
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
handlers.push(() => {
|
|
|
|
|
// tslint:disable-next-line: no-any
|
|
|
|
|
(win as any).FontFace = originalFontFace;
|
|
|
|
|
win.FontFace = originalFontFace;
|
|
|
|
|
});
|
|
|
|
|
handlers.push(restoreHandler);
|
|
|
|
|
|
|
|
|
|
@@ -923,6 +927,11 @@ export function initObservers(
|
|
|
|
|
o: observerParam,
|
|
|
|
|
hooks: hooksParam = {},
|
|
|
|
|
): listenerHandler {
|
|
|
|
|
const currentWindow = o.doc.defaultView; // basically document.window
|
|
|
|
|
if (!currentWindow) {
|
|
|
|
|
return () => {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mergeHooks(o, hooks);
|
|
|
|
|
const mutationObserver = initMutationObserver(
|
|
|
|
|
o.mutationCb,
|
|
|
|
|
@@ -980,8 +989,6 @@ export function initObservers(
|
|
|
|
|
o.mirror,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const currentWindow = o.doc.defaultView as Window; // basically document.window
|
|
|
|
|
|
|
|
|
|
const styleSheetObserver = initStyleSheetObserver(
|
|
|
|
|
o.styleSheetRuleCb,
|
|
|
|
|
currentWindow,
|
|
|
|
|
@@ -994,20 +1001,21 @@ export function initObservers(
|
|
|
|
|
);
|
|
|
|
|
const canvasMutationObserver = o.recordCanvas
|
|
|
|
|
? initCanvasMutationObserver(
|
|
|
|
|
o.canvasMutationCb,
|
|
|
|
|
currentWindow,
|
|
|
|
|
o.blockClass,
|
|
|
|
|
o.mirror,
|
|
|
|
|
) : () => {};
|
|
|
|
|
const fontObserver = o.collectFonts ? initFontObserver(o.fontCb, o.doc) : () => {};
|
|
|
|
|
o.canvasMutationCb,
|
|
|
|
|
currentWindow,
|
|
|
|
|
o.blockClass,
|
|
|
|
|
o.mirror,
|
|
|
|
|
)
|
|
|
|
|
: () => {};
|
|
|
|
|
const fontObserver = o.collectFonts
|
|
|
|
|
? initFontObserver(o.fontCb, o.doc)
|
|
|
|
|
: () => {};
|
|
|
|
|
// plugins
|
|
|
|
|
const pluginHandlers: listenerHandler[] = [];
|
|
|
|
|
for (const plugin of o.plugins) {
|
|
|
|
|
pluginHandlers.push(plugin.observer(
|
|
|
|
|
plugin.callback,
|
|
|
|
|
currentWindow,
|
|
|
|
|
plugin.options,
|
|
|
|
|
));
|
|
|
|
|
pluginHandlers.push(
|
|
|
|
|
plugin.observer(plugin.callback, currentWindow, plugin.options),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
|