不小心在window.open请求头 中装了chromium,怎么都删不掉,请求帮助!

4001人阅读
Javascript(17)
1、为什么会有跨域问题的存在?
&& JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象,即同源政策。
2、什么是同源?
&& 1995年,同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。
& 最初,它的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页&同源&。所谓&同源&指的是&三个相同&。
& (1)协议相同
& (2)域名相同
& (3)端口相同
具体实例 &比如:/zw/index.html这个网站,它的协议是http://,域名是,端口号是80(默认端口可以省略),它的同源情况如下:
& &①、/zwxk/manager.html & &同源
& &②、https:///zw/index.html & 不同源(协议不同)
& &③、http:///zw/index.html &不同源(域名不同)
& &④、:81zw/index.html & 不同源(端口号不同)
3、同源政策的目的
同源策略的目的是为了保证用户信息的安全。防止恶意的网站盗取数据。
设想这样一个情景:A网站是一家银行,用户登录以后,又去浏览其他的网站B,如果网站B可以读取A网站的Cookie,会发生什么问题?
显然,如果Cookie包含隐私(比如存款总额),这些信息就会泄露,更可怕的是,Cookie往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒用户,为所欲为。因为浏览器同时还规定,提交表单不受同源策略的限制。
由此可见,“同源政策”的必要性,否则Cookie可以共享,互联网就毫无安全可言了。
3、非同源限制范围
随着互联网的发展,“同源政策”越来越严格。目前,如果非同源,共有三种行为受到限制。
& (1)Cookie、LocalStorage和IndexDB无法获取。
& (2)DOM无法获得。
& (3)AJAX请求不能发送。
虽然这些限制是必要的,但是有时很不方便,合理的用途也受到影响。下面将介绍如何规避上面三种限制。
4-1、解决跨域一:Cookie如何实现跨域
Cookie是服务器写入浏览器的一段信息,只有同源的网页才能共享,但是,两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain共Cookie。
举例来说,A网站是:http:
& B网站是:http:
那么只需设置相同的document.domain,两个网页就可共享Cookie。
document.domain = &#';
现在,A网页通过脚本设置一个Cookie。
document.Cookie = &test1=hello&;
B网页就能读到这个Cookie。
var getCookie = document.
注意:这种方法只适用于Cookie和iframe窗口,LocalStorage和IndexDB无法通过这种方法规避,而要使用下文将介绍的PostMessage API。
另外,服务器也可以在设置Cookie的时候,指定Cookie的所属域名为一级域名,比如:.qq.com
Set-Cookie:key=domain=&span style=&color:#cc0000;&&.qq.com&/span&;path=/
这样的话,二级域名和三级域名不用做任何设置,都可以读取这个Cookie。
4-2、解决跨域问题二:如何跨域获取DOM。
如果两个网页不同源,就无法拿到对方的DOM。典型的例子是iframe窗口和window.open方法打开的窗口,它们与父窗口无法通信。
& &比如,父窗口运行下面的命令,如果iframe窗口不是同源将会报错。
document.getElementById(&iframe&).contentWindow.document
& &上面命令中,父窗口想获取子窗口的DOM,应为跨源导致报错。
& &反之亦然,子窗口获取主窗口的DOM也会报错。
window.parent.document.body
& &如果两个窗口一级域名相同,只是二级域名不同,那么设置4-1介绍的document.domain属性,就可规避同源政策,拿到DOM。
& &对于完全不相同的网站,目前有三种方法,可以解决跨域窗口的通信问题。
& &(1)片段识别符(fragment identifier)
& &(2)window.name
& &(3)跨文档通信API(Cross-document messaging)
&4-2-1:片段识别符
& & &片段识别符指的是,URL的#号后面的部分,比如http://qq.com/x.html#fragment的#fragment。如果只是改变片段标识符,页面将不会重新刷新、
& 父窗口可以把信息,写入子窗口的片段标识符。
var src = originURL+'#'+
document.getElementById('iframe').src =
& 子窗口通过监听hashchange事件得到通知
  window.onhashchange = checkM
  function checkMessage(){
  var message = window.location.
  //...
&同样的,子窗口也可以改变父窗口的片段标识符。
parent.location.href = target+&#&+
4-2-2:window.name:
浏览器窗口有window.name属性。这个属性的最大特点是,无论是否同源,只要在同一个窗口里,前一个网页设置这个属性,后一个网页就可以读取它。
父窗口先发开一个子窗口,载入一个不同源的网页,该网页将信息写入window.name属性。
window.name =
接着,子窗口跳回一个与主窗口同域的网址。
location = '/xxx.html';
& 然后,主窗口就可以读取子窗口的window.name了。
var data = document.getElementById('iframe').contentWindow.
优点:window.name容量很大,可以防止非常长的字符串;
缺点:必须监听子窗口window.name属性的变化,会影响网页性能。
4-2-3:跨文档消息传输window.postMessage:
上面两种方法都属于破解,HTML5为解决这个问题,引入一个全新的API:跨文档消息传输Cross Document Messaging。
下一代浏览器都将支持这个功能:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。&
Facebook已经使用了这个功能,用postMessage支持基于web的实时消息传递。
使用方法:otherWindow.postMessage(message, targetOrigin);
otherWindow: 对接收信息页面的window的引用。可以是页面中iframe的contentWindow属性;window.open的返回值;
通过name或下标从window.frames取到的值。
message: 具体的信息内容,string类型。
targetOrigin: 接受消息的窗口的源(origin),即“协议+域名+端口”。也可以设为“*”,表示不限制域名,向所有窗口发送。
message事件的事件对象event,提供一下三个属性:
(1).event.source:发送消息的窗口
(2).event.origin:消息发向的网站
(3).event.data:消息内容
具体实例:
<//index.html中的代码:
&iframe id=&ifr& src=&/index.html&&&/iframe&
&script type=&text/javascript&&
window.onload = function() {
var ifr = document.getElementById(&#39;ifr&#39;);
var targetOrigin = &#39;http://b.com&#39;;
// 若写成&#39;http://b.com/c/proxy.html&#39;效果一样
// 若写成&#39;http://c.com&#39;就不会执行postMessage了
ifr.contentWindow.postMessage(&#39;I was there!&#39;, targetOrigin);
</index.html中的代码:
&script type=&text/javascript&&
window.addEventListener(&#39;message&#39;, function(event){
// 通过origin属性判断消息来源地址
if (event.origin == &#39;http://a.com&#39;) {
alert(event.data);
// 弹出&I was there!&
alert(event.source);
// 对a.com、index.html中window对象的引用
// 但由于同源策略,这里event.source不可以访问window对象
}, false);
4-3、如何解决跨域LocalStorage。
通过window.postMessage,读写其他窗口的LocalStorage也成为了可能。下面是一个例子,主窗口写入iframe子窗口的LocalStorage。
window.onmessage = function(e){
&#160; if(e.origin !== &#39;&#39;){
&#160; &#160;
&#160; var payload = JSON.parse(e.data);
&#160; localStorage.setItem(payload.key,JSON.stringify(payload.data));
上面代码中,子窗口将父窗口发送来的消息,写入自己的LocalStorage。
父窗口发送消息的代码如下.
var win = document.getElementsByTagName(&#39;iframe&#39;)[0].contentW
var obj = {name:&#39;Jack&#39;};
win.postMessage(JSON.stringify({key:&#39;storage&#39;,data:obj}),&#39;&#39;);
加强版的子窗口接受消息的代码如下。
window.onmessage = function(e) {
if (e.origin !== &#39;&#39;)
var payload = JSON.parse(e.data);
switch (payload.method) {
case &#39;set&#39;:
localStorage.setItem(payload.key, JSON.stringify(payload.data));
case &#39;get&#39;:
var parent = window.
var data = localStorage.getItem(payload.key);
parent.postMessage(data, &#39;&#39;);
case &#39;remove&#39;:
localStorage.removeItem(payload.key);
加强版的父窗口发送消息代码如下:
var win = document.getElementsByTagName(&#39;iframe&#39;)[0].contentW
var obj = { name: &#39;Jack&#39; };
// 存入对象
win.postMessage(JSON.stringify({key: &#39;storage&#39;, method: &#39;set&#39;, data: obj}), &#39;&#39;);
// 读取对象
win.postMessage(JSON.stringify({key: &#39;storage&#39;, method: &get&}), &*&);
window.onmessage = function(e) {
if (e.origin != &#39;&#39;)
console.log(JSON.parse(e.data).name);
4-4、如何解决AJAX的跨域:
同源政策规定,AJAX请求只能发给同源的网址,否则就报错。
除了架设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),有三种方法规避这个限制。
(1)JSONP
(2)WebSocket
4-4-1、JSONP解决AJAX跨域问题:
JSONP是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,老式浏览器全部支持,服务器改造非常小。
它的基本思想是,网页通过添加一个&script&元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
首先,网页动态插入&script&元素,由它向跨源网址发出请求。
function addScriptTag(src) {
var script = document.createElement(&#39;script&#39;);
script.setAttribute(&type&,&text/javascript&);
script.src =
document.body.appendChild(script);
window.onload = function () {
addScriptTag(&#39;/ip?callback=foo&#39;);
function foo(data) {
console.log(&#39;Your public IP address is: &#39; + data.ip);
上面代码通过动态添加&script&元素,向服务器发出请求。注意,该请求的查询字符串有一个callback参数,用来指定回调函数的名字,这对于JSONP是必需的。
服务器收到这个请求以后,会将数据放在回调函数的参数位置返回。
&ip&: &8.8.8.8&
由于&script&元素请求的脚本,直接作为代码运行。这时,只要浏览器定义了foo函数,该函数就会立即调用。作为参数的JSON数据被视为JavaScript对象,而不是字符串,因此避免了使用JSON.parse的步骤。
4-4-2、通过webSocket解决AJAX跨域
WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。
& &下面是一个例子,浏览器发出的WebSocket请求的头信息(摘自维基百科)。
GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
上面代码中,有一个字段是Origin,表示该请求的请求源(origin),即发自哪个域名。
正是因为有了Origin这个字段,所以WebSocket才没有实行同源政策。因为服务器可以根据这个字段,判断是否许可本次通信。如果该域名在白名单内,服务器就会做出如下回应。
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
4-4-3、通过CORS解决AJAX跨域
CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本解决方法。相比JSONP只能发GET请求,CORS允许任何类型的请求。
定义:CORS其实出现时间不短了,它在维基百科上的定义是:跨域资源共享(CORS)是一种网络浏览器的技术规范,它为Web服务器定义了一种方式,允许网页从不同的域访问其资源。而这种访问是被同源策略所禁止的。CORS系统定义了一种浏览器和服务器交互的方式来确定是否允许跨域请求。
它是一个妥协,有更大的灵活性,但比起简单地允许所有这些的要求来说更加安全。而W3C的官方文档目前还是工作草案,但是正在朝着W3C推荐的方向前进。
&& 简言之,CORS就是为了让AJAX可以实现可控的跨域访问而生的。
以往的解决方案:
&&以前要实现跨域访问,可以通过JSONP、Flash或者服务器中转的方式来实现,但是现在我们有了CORS。
&&CORS与JSONP相比,无疑更为先进、方便和可靠。
&&&&1、 JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。
&&&&2、 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。
& & 3、&JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS(这部分会在后文浏览器支持部分介绍)。
详细内容:
要使用CORS,我们需要了解前端和服务器端的使用方法。
& &以前我们使用Ajax,代码类&#20284;于如下的方式:
var xhr = new XMLHttpRequest();
xhr.open(&GET&, &/relativeHref&, true);
xhr.send();
&&&&这里的“/relativeHref”是本域的相对路径。
&&&&如果我们要使用CORS,相关Ajax代码可能如下所示:
var xhr = new XMLHttpRequest();
xhr.open(&GET&, &http://blog.csdn.net/hfahe&, true);
xhr.send();
&&&&请注意,代码与之前的区别就在于相对路径换成了其他域的绝对路径,也就是你要跨域访问的接口地址。
&&&&我们还必须提供浏览器回退功能检测和支持,避免浏览器不支持的情况。
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if (&withCredentials& in xhr) {
// 此时即支持CORS的情况
// 检查XMLHttpRequest对象是否有“withCredentials”属性
// “withCredentials”仅存在于XMLHTTPRequest2对象里
xhr.open(method, url, true);
} else if (typeof!= &undefined&) {
// 否则检查是否支持XDomainRequest,IE8和IE9支持
// XDomainRequest仅存在于IE中,是IE用于支持CORS请求的方式
xhr = new XDomainRequest();
xhr.open(method, url);
// 否则,浏览器不支持CORS
var xhr = createCORSRequest(&#39;GET&#39;, url);
if (!xhr) {
throw new Error(&#39;CORS not supported&#39;);
现在如果直接使用上面的脚本进行请求,会看到浏览器里控制台的报错如下:
错误显示的很明显,这是因为我们还未设置Access-Control-Allow-Origin头。
服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。
HTTP 头的设置方法有很多,http://enable-cors.org/这篇文章里对各种服务器和语言的设置都有详细的介绍:
①、Apache:Apache需要使用mod_headers模块来激活HTTP头的设置,它默认是激活的。你只需要在Apache配置文件的&Directory&,
&Location&, &Files&或&VirtualHost&的配置里加入以下内容即可:
Header set Access-Control-Allow-Origin *
&&& &②、PHP:只需要使用如下的代码设置即可。
header(&Access-Control-Allow-Origin:*&);
&&& &以上的配置的含义是允许任何域发起的请求都可以获取当前服务器的数据。当然,这样有很大的危险性,恶意站点可能通过XSS攻击我们的服务器。所以我们应该尽量有针对性的对限制安全的来源,例如下面的设置使得只有http://blog.csdn.net这个域才能跨域访问服务器的API。
Access-Control-Allow-Origin: http://blog.csdn.net
③、Node的配置(基于express):
var express = require(&#39;express&#39;);
var app = express();
//设置跨域访问
app.all(&#39;*&#39;, function(req, res, next) {
res.header(&Access-Control-Allow-Origin&, &*&);
res.header(&Access-Control-Allow-Headers&, &X-Requested-With&);
res.header(&Access-Control-Allow-Methods&,&PUT,POST,GET,DELETE,OPTIONS&);
res.header(&X-Powered-By&,&#39; 3.2.1&#39;)
res.header(&Content-Type&, &application/charset=utf-8&);
app.get(&#39;/auth/:id/:password&#39;, function(req, res) {
res.send({id:req.params.id, name: req.params.password});
app.listen(3000);
浏览器支持情况
上图为各浏览器对于CORS的支持情况(绿色为支持,数据来源:/cors),看起来相当乐观。主流浏览器都已基本提供对跨域资源共享的支持,所以,CORS才会在国外使用的如此普遍。
从所有的浏览器都支持来看,CORS将成为未来跨域访问的标准解决方案。无论是自己服务器间的跨域访问,还是开放平台为第三方提供API,都将采用这种统一的解决方案,因为它简单、高效,受到所有主流浏览器的支持。它非常重要,也会让我们的网络变得更加开放。
本文部分内容转自/blog/2016/04/same-origin-policy.html
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:28789次
排名:千里之外
原创:28篇
(2)(9)(10)(1)(11)WebKit(135)
常见的UI库的绘制逻辑
任何一个成熟的界面框架都有一个相当复杂的结构,消息循环的处理、控件的布局与绘制、焦点的管理以及资源的存取等等,Chromium里的界面框架也不例外,尤其采用的MVC设计方式更是增添了代码结构的复杂度。这里并不打算讨论Chromium的界面框架,本文感兴趣的只是Chromium的UI绘制部分,确切地说应该是引入Aura架构之后控件渲染的硬件加速支持。
在常见的DirectUI实现(Windows平台)中,绘制逻辑一般如下:最外层带HWND句柄的的Window在接收到WM_PAINT消息时,会通过BeginPaint函数获得一个窗口对应的绘制DC,然后根据这个绘制DC创建一个相应的内存DC,之后遍历Window内自绘的控件(呈树型结构),每个控件计算需要更新区域与自己区域的交集,在该内存DC上绘制交集区域对应的控件部位,最后由BitBlt系列的API将内存DC拷贝到绘制DC上,从而完成一整套的渲染逻辑。没有语言功底的人用文字来描述流程逻辑,会显得相当苍白无力,还是附上一张简单的流程图吧。
整体流程结构上很清晰明了,但是实现起来很是繁琐,尤其是处理控件的层级、可视性、绘制区域的计算等逻辑。Chromium中UI框架的软件渲染流程也大致是这个流程,只是引入了硬件渲染后,增加了合成层的概念,为了结构上的一致性,软件渲染流程也经过cc层,路由一大圈,最终绘制在软件渲染提供的OutputSurface上,具体可参见SoftwareOutputDeviceWin实现,Chromium的软件渲染部分在探究CC库的时候会深入研究。
引入Aura框架后的Chromium UI库的绘制逻辑
&&&&&&&&& 在普遍的DirectUI库实现中,一般都是采用软件渲染,也就是通过一系列的GDI函数在DC上绘制,软件渲染一旦遇到刷新频率比较高的情况下,比如视频画面、游戏画面等,绘制效率就力不从心了,流畅度体验下降的厉害,所以播放视频或者游戏都用GPU进行硬件渲染,然而Windows下硬件渲染一般都需要提供窗口句柄HWND,比如DirectShow中的渲染组件VMR Filter, 但是在DirectUI框架中加入一个带HWND的子窗口是种很要命的情况,这样就完全破坏了自绘体系,任何完全自绘的控件都无法位于HWND子窗口之上,焦点逻辑、消息路由等体系都会遭受不同程度的破坏。退一步讲,就算一个成熟的DirectUI库对包容子HWND窗口逻辑做的足够好,那试想一下如果一个ui界面中如果有多处需要HWND的情况,那也是很糟糕的事。总之,在我看来,在DirectUI框架中加入带HWND的子窗口完全就是悖论,就是对实际应用场景的一种妥协。还有,DirectUI的一大特色就是完全自绘,这样就容易开发出绚丽多彩的界面,酷炫界面当然少不了动画逻辑,动画的渲染如果能用上GPU也是一大助力。废话了这么多,总之,能够支持硬件渲染对DirectUI库来说是很有必要的。
&&&&&&&&& 非常荣幸,Chromium UI库就支持硬件渲染,为此还引入了Aura框架结构来管理UI的渲染底层。Chromium UI框架渲染逻辑涉及到的结构图大致如下:
在介绍渲染流程之前之前,有必要理解一下Aura结构,依据我的理解, Aura中的Window类应该就是Aura框架中的窗口的概念,Window同样采取树型组织结构,从而WindowTreeHost类的作用就不难理解了,就是作为Window树的宿主,WindowTreeHost内部创建一个顶层的Window作为所有的Window树的根节点。WindowTreeHost在不同平台下有着不同的实现,在windows下的实现类是DesktopWindowTreeHostWin, 其维护一个HWNDMessageHandler对象,用来处理windows平台下的窗口的创建、消息处理等逻辑,HWNDMessageHandler从
WindowImpl派生,负责处理庞大的Windows消息处理,并将处理逻辑通过HWNDMessageHandlerDelegate接口传递给DesktopWindowTreeHostWin处理,比如,WM_PAINT消息的处理逻辑就是通过这种方式委托给DesktopWindowTreeHostWin的HandlePaint函数来处理。
在引入Aura之前,Widget类直接HWNDMessageHandler进行对接,引入Aura之后,Widget与HWND脱离开来,不过逻辑上仍然作为对外开发接口中的顶层窗口。
views框架为Widget配备一个DesktopNativeWidgetAura对象作为与Aura层的适配,如图所示,DesktopNativeWidgetAura逻辑上只维护了一个Window对象,即content_window_成员,该Window对应整个的Widget窗口层级,也就是说整个Widget包括其内部的View树都属于Aura中的一个窗口层。
&&&&&&&&& 在Aura体系中,Window和Layer为一一对应的关系,从而很好地表示出每个窗口就是一个渲染层的概念。当渲染引擎渲染之前,需要收集每个Layer的绘制逻辑时,Layer对象通过LayerDelegate接口的OnPaintLayer方法来将逻辑委托给与其对应的Window类。同样,DesktopNativeWidgetAura为Widget维护了一个Window对象,它就有义务从Window对象中将绘制逻辑通过WindowDelegate接口承接过来,然后通过NativeWidgetDelegate接口将该逻辑抛给Widget对象,Widget对象响应OnNativeWidgetPaint函数,遍历自身的View树,往画布上添砖加瓦。
&&&&&&&&& 在这里需要补充一下,Widget的View也可以持有Layer对象,刚才的结构图中实在不便标出,View同样实现了LayerDelegate接口,控件可以根据需要创建属于自己的Layer层,并将其添加到DesktopNativeWidgetAura成员content_window_对应的Layer层的子节点中(再次嵌套补充一下,这里说的Layer是ui层的Layer,添加到其子节点,为的是添加到与ui层Layer对应的cc层的Layer的树层级中,cc层的Layer树才是真正的渲染树,ui层的Layer只是为了方便Aura访问做的一层适配。有点绕了,以后讨论cc库的时候再细说吧)。通过调用View的SetPaintToLayer方法,View就会创建自己的Layer层。此时View直接实现OnPaintLayer方法来处理绘制即可,而且绘制的层级在不创建Layer的View控件之上。如果要创建一个显示视频的控件,可以考虑创建一个属于自己的Layer层,从而在独立的层上绘制视频数据。啰嗦了这么多,还是配上一张序列图啊,一图抵千言:
cc库的逻辑以后再开始重点研究,这里姑且就当黑盒处理。这个流程中,绘制的驱动由windows消息WM_PAINT的响应来驱动,这是典型的软件渲染流程,另外可以调用View控件的SchedulePaint方法来重绘该控件,重绘的流程是找到与View绑定的Layer对象,如果没有绑定则一直向上找,最顶层的Widget可以通过GetLayer方法访问到DesktopNativeWidgetAura成员content_window_对应的Layer。找到Layer后调用Layer的SchedulePaint函数,从而驱动Compositor出发绘制流程。
本文就先介绍到这里,其实这里面还有很多逻辑可扒,比如绘制流程一旦触发,怎么确定单个Layer或View是否需要重新绘制等。时间有限,精力有限,还是留点激情稍后去研究CC模块为好
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:31862次
积分:2831
积分:2831
排名:第9140名
原创:237篇
转载:156篇
(7)(1)(5)(45)(21)(43)(82)(179)(17)3314人阅读
Javascript(59)
Chromium :
* Copyright (C) 2007 Apple Inc.
All rights reserved.
* Copyright (C) 2013 Google Inc. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of Apple Computer, Inc. (&Apple&) nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS &AS IS& AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* @param {!InjectedScriptHostClass} InjectedScriptHost
* @param {!Window} inspectedWindow
* @param {number} injectedScriptId
(function (InjectedScriptHost, inspectedWindow, injectedScriptId) {
* Protect against Object overwritten by the user code.
* @suppress {duplicate}
var Object = /** @type {function(new:Object, *=)} */ ({}.constructor);
* @param {!Array.&T&} array
* @param {...} var_args
* @template T
function push(array, var_args)
for (var i = 1; i & arguments. ++i)
array[array.length] = arguments[i];
* @param {!Arguments.&T&} array
* @param {number=} index
* @return {!Array.&T&}
* @template T
function slice(array, index)
var result = [];
for (var i = index || 0, j = 0; i & array. ++i, ++j)
result[j] = array[i];
* @param {!Array.&T&} array1
* @param {!Array.&T&} array2
* @return {!Array.&T&}
* @template T
function concat(array1, array2)
var result = [];
for (var i = 0; i & array1. ++i)
push(result, array1[i]);
for (var i = 0; i & array2. ++i)
push(result, array2[i]);
* @param {*} obj
* @return {string}
* @suppress {uselessCode}
function toString(obj)
// We don&#39;t use String(obj) because String could be overridden.
// Also the (&& + obj) expression may throw.
return && +
} catch (e) {
var name = InjectedScriptHost.internalConstructorName(obj) || InjectedScriptHost.subtype(obj) || (typeof obj);
return &#&& + name + &&&;
* @param {*} obj
* @return {string}
function toStringDescription(obj)
if (typeof obj === &number& && obj === 0 && 1 / obj & 0)
return &-0&; // Negative zero.
return toString(obj);
* Please use this bind, not the one from Function.prototype
* @param {function(...)} func
* @param {?Object} thisObject
* @param {...} var_args
* @return {function(...)}
function bind(func, thisObject, var_args)
var args = slice(arguments, 2);
* @param {...} var_args
function bound(var_args)
return InjectedScriptHost.callFunction(func, thisObject, concat(args, slice(arguments)));
bound.toString = function()
return &bound: & + toString(func);
* @param {T} obj
* @return {T}
* @template T
function nullifyObjectProto(obj)
if (obj && typeof obj === &object&)
obj.__proto__ =
* @param {*} obj
* @return {boolean}
function isUInt32(obj)
return typeof obj === &number& && obj &&& 0 === obj && (obj & 0 || 1 / obj & 0);
* FireBug&#39;s array detection.
* @param {*} obj
* @return {boolean}
function isArrayLike(obj)
if (typeof obj !== &object&)
if (typeof obj.splice === &function&)
return isUInt32(obj.length);
} catch (e) {
* @param {number} a
* @param {number} b
* @return {number}
function max(a, b)
return a & b ? a :
* FIXME: Remove once ES6 is supported natively by JS compiler.
* @param {*} obj
* @return {boolean}
function isSymbol(obj)
var type =
return (type === &symbol&);
* @constructor
var InjectedScript = function()
/** @type {number} */
this._lastBoundObjectId = 1;
/** @type {!Object.&number, (!Object|symbol)&} */
this._idToWrappedObject = { __proto__: null };
/** @type {!Object.&number, string&} */
this._idToObjectGroupName = { __proto__: null };
/** @type {!Object.&string, !Array.&number&&} */
this._objectGroups = { __proto__: null };
/** @type {!Object.&string, !Object&} */
this._modules = { __proto__: null };
* @type {!Object.&string, boolean&}
InjectedScript.primitiveTypes = {
&undefined&: true,
&boolean&: true,
&number&: true,
&string&: true,
__proto__: null
InjectedScript.prototype = {
* @param {*} object
* @return {boolean}
isPrimitiveValue: function(object)
// FIXME(33716): typeof document.all is always &#39;undefined&#39;.
return InjectedScript.primitiveTypes[typeof object] && !this._isHTMLAllCollection(object);
* @param {*} object
* @param {string} groupName
* @param {boolean} canAccessInspectedWindow
* @param {boolean} generatePreview
* @return {!RuntimeAgent.RemoteObject}
wrapObject: function(object, groupName, canAccessInspectedWindow, generatePreview)
if (canAccessInspectedWindow)
return this._wrapObject(object, groupName, false, generatePreview);
return this._fallbackWrapper(object);
* @param {*} object
* @return {!RuntimeAgent.RemoteObject}
_fallbackWrapper: function(object)
var result = { __proto__: null };
result.type =
if (this.isPrimitiveValue(object))
result.value =
result.description = toString(object);
return /** @type {!RuntimeAgent.RemoteObject} */ (result);
* @param {boolean} canAccessInspectedWindow
* @param {!Object} table
* @param {!Array.&string&|string|boolean} columns
* @return {!RuntimeAgent.RemoteObject}
wrapTable: function(canAccessInspectedWindow, table, columns)
if (!canAccessInspectedWindow)
return this._fallbackWrapper(table);
var columnNames =
if (typeof columns === &string&)
columns = [columns];
if (InjectedScriptHost.subtype(columns) === &array&) {
columnNames = [];
for (var i = 0; i & columns. ++i)
columnNames[i] = toString(columns[i]);
return this._wrapObject(table, &console&, false, true, columnNames, true);
* @param {*} object
inspectNode: function(object)
this._inspect(object);
* @param {*} object
* @return {*}
_inspect: function(object)
if (arguments.length === 0)
var objectId = this._wrapObject(object, &&);
var hints = { __proto__: null };
InjectedScriptHost.inspect(objectId, hints);
* This method cannot throw.
* @param {*} object
* @param {string=} objectGroupName
* @param {boolean=} forceValueType
* @param {boolean=} generatePreview
* @param {?Array.&string&=} columnNames
* @param {boolean=} isTable
* @return {!RuntimeAgent.RemoteObject}
* @suppress {checkTypes}
_wrapObject: function(object, objectGroupName, forceValueType, generatePreview, columnNames, isTable)
return new InjectedScript.RemoteObject(object, objectGroupName, forceValueType, generatePreview, columnNames, isTable);
} catch (e) {
var description = injectedScript._describe(e);
} catch (ex) {
var description = &&failed to convert exception to string&&;
return new InjectedScript.RemoteObject(description);
* @param {!Object|symbol} object
* @param {string=} objectGroupName
* @return {string}
_bind: function(object, objectGroupName)
var id = this._lastBoundObjectId++;
this._idToWrappedObject[id] =
var objectId = &{\&injectedScriptId\&:& + injectedScriptId + &,\&id\&:& + id + &}&;
if (objectGroupName) {
var group = this._objectGroups[objectGroupName];
if (!group) {
group = [];
this._objectGroups[objectGroupName] =
push(group, id);
this._idToObjectGroupName[id] = objectGroupN
return objectId;
* @param {string} objectId
* @return {!Object}
_parseObjectId: function(objectId)
return nullifyObjectProto(/** @type {!Object} */ (InjectedScriptHost.eval(&(& + objectId + &)&)));
* @param {string} objectGroupName
releaseObjectGroup: function(objectGroupName)
if (objectGroupName === &console&)
delete this._lastR
var group = this._objectGroups[objectGroupName];
if (!group)
for (var i = 0; i & group. i++)
this._releaseObject(group[i]);
delete this._objectGroups[objectGroupName];
* @param {string} objectId
setLastEvaluationResult: function(objectId)
var parsedObjectId = this._parseObjectId(objectId);
var object = this._objectForId(parsedObjectId);
this._lastResult =
* @param {string} methodName
* @param {string} args
* @return {*}
dispatch: function(methodName, args)
var argsArray = /** @type {!Array.&*&} */ (InjectedScriptHost.eval(&(& + args + &)&));
var result = InjectedScriptHost.callFunction(this[methodName], this, argsArray);
if (typeof result === &undefined&) {
inspectedWindow.console.error(&Web Inspector error: InjectedScript.%s returns undefined&, methodName);
* @param {string} objectId
* @param {boolean} ownProperties
* @param {boolean} accessorPropertiesOnly
* @return {!Array.&!RuntimeAgent.PropertyDescriptor&|boolean}
getProperties: function(objectId, ownProperties, accessorPropertiesOnly)
var parsedObjectId = this._parseObjectId(objectId);
var object = this._objectForId(parsedObjectId);
var objectGroupName = this._idToObjectGroupName[parsedObjectId.id];
if (!this._isDefined(object) || isSymbol(object))
object = /** @type {!Object} */ (object);
var descriptors = this._propertyDescriptors(object, ownProperties, accessorPropertiesOnly);
// Go over properties, wrap object values.
for (var i = 0; i & descriptors. ++i) {
var descriptor = descriptors[i];
if (&get& in descriptor)
descriptor.get = this._wrapObject(descriptor.get, objectGroupName);
if (&set& in descriptor)
descriptor.set = this._wrapObject(descriptor.set, objectGroupName);
if (&value& in descriptor)
descriptor.value = this._wrapObject(descriptor.value, objectGroupName);
if (!(&configurable& in descriptor))
descriptor.configurable =
if (!(&enumerable& in descriptor))
descriptor.enumerable =
if (&symbol& in descriptor)
descriptor.symbol = this._wrapObject(descriptor.symbol, objectGroupName);
* @param {string} objectId
* @return {!Array.&!Object&|boolean}
getInternalProperties: function(objectId)
var parsedObjectId = this._parseObjectId(objectId);
var object = this._objectForId(parsedObjectId);
var objectGroupName = this._idToObjectGroupName[parsedObjectId.id];
if (!this._isDefined(object) || isSymbol(object))
object = /** @type {!Object} */ (object);
var descriptors = [];
var internalProperties = InjectedScriptHost.getInternalProperties(object);
if (internalProperties) {
for (var i = 0; i & internalProperties. i++) {
var property = internalProperties[i];
var descriptor = {
name: property.name,
value: this._wrapObject(property.value, objectGroupName),
__proto__: null
push(descriptors, descriptor);
* @param {string} functionId
* @return {!DebuggerAgent.FunctionDetails|string}
getFunctionDetails: function(functionId)
var parsedFunctionId = this._parseObjectId(functionId);
var func = this._objectForId(parsedFunctionId);
if (typeof func !== &function&)
return &Cannot resolve function by id.&;
var details = nullifyObjectProto(/** @type {!DebuggerAgent.FunctionDetails} */ (InjectedScriptHost.functionDetails(func)));
if (&rawScopes& in details) {
var objectGroupName = this._idToObjectGroupName[parsedFunctionId.id];
var rawScopes = details[&rawScopes&];
delete details[&rawScopes&];
var scopes = [];
for (var i = 0; i & rawScopes. ++i)
scopes[i] = InjectedScript.CallFrameProxy._createScopeJson(rawScopes[i].type, rawScopes[i].object, objectGroupName);
details.scopeChain =
* @param {string} objectId
* @return {!Array.&!Object&|string}
getCollectionEntries: function(objectId)
var parsedObjectId = this._parseObjectId(objectId);
var object = this._objectForId(parsedObjectId);
if (!object || typeof object !== &object&)
return &Could not find object with given id&;
var entries = InjectedScriptHost.collectionEntries(object);
if (!entries)
return &Object with given id is not a collection&;
var objectGroupName = this._idToObjectGroupName[parsedObjectId.id];
for (var i = 0; i & entries. ++i) {
var entry = nullifyObjectProto(entries[i]);
if (&key& in entry)
entry.key = this._wrapObject(entry.key, objectGroupName);
entry.value = this._wrapObject(entry.value, objectGroupName);
entries[i] =
* @param {string} objectId
releaseObject: function(objectId)
var parsedObjectId = this._parseObjectId(objectId);
this._releaseObject(parsedObjectId.id);
* @param {number} id
_releaseObject: function(id)
delete this._idToWrappedObject[id];
delete this._idToObjectGroupName[id];
* @param {!Object} object
* @param {boolean=} ownProperties
* @param {boolean=} accessorPropertiesOnly
* @return {!Array.&!Object&}
_propertyDescriptors: function(object, ownProperties, accessorPropertiesOnly)
var descriptors = [];
var propertyProcessed = { __proto__: null };
* @param {?Object} o
* @param {!Array.&string|symbol&} properties
function process(o, properties)
for (var i = 0; i & properties. ++i) {
var property = properties[i];
if (propertyProcessed[property])
var name =
if (isSymbol(property))
name = injectedScript._describe(property);
propertyProcessed[property] =
var descriptor = nullifyObjectProto(InjectedScriptHost.suppressWarningsAndCallFunction(Object.getOwnPropertyDescriptor, Object, [o, property]));
if (descriptor) {
if (accessorPropertiesOnly && !(&get& in descriptor || &set& in descriptor))
// Not all bindings provide proper descriptors. Fall back to the writable, configurable property.
if (accessorPropertiesOnly)
descriptor = { name: name, value: o[property], writable: false, configurable: false, enumerable: false, __proto__: null };
if (o === object)
descriptor.isOwn =
push(descriptors, descriptor);
} catch (e) {
// Silent catch.
} catch (e) {
if (accessorPropertiesOnly)
var descriptor = { __proto__: null };
descriptor.value =
descriptor.wasThrown =
descriptor.name =
if (o === object)
descriptor.isOwn =
if (isSymbol(property))
descriptor.symbol =
push(descriptors, descriptor);
for (var o = this._isDefined(o); o = o.__proto__) {
// First call Object.keys() to enforce ordering of the property descriptors.
process(o, Object.keys(/** @type {!Object} */ (o)));
process(o, Object.getOwnPropertyNames(/** @type {!Object} */ (o)));
if (Object.getOwnPropertySymbols)
process(o, Object.getOwnPropertySymbols(/** @type {!Object} */ (o)));
if (ownProperties) {
if (object.__proto__ && !accessorPropertiesOnly)
push(descriptors, { name: &__proto__&, value: object.__proto__, writable: true, configurable: true, enumerable: false, isOwn: true, __proto__: null });
* @param {string} expression
* @param {string} objectGroup
* @param {boolean} injectCommandLineAPI
* @param {boolean} returnByValue
* @param {boolean} generatePreview
* @return {*}
evaluate: function(expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview)
return this._evaluateAndWrap(null, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview);
* @param {string} objectId
* @param {string} expression
* @param {string} args
* @param {boolean} returnByValue
* @return {!Object|string}
callFunctionOn: function(objectId, expression, args, returnByValue)
var parsedObjectId = this._parseObjectId(objectId);
var object = this._objectForId(parsedObjectId);
if (!this._isDefined(object))
return &Could not find object with given id&;
if (args) {
var resolvedArgs = [];
var callArgs = /** @type {!Array.&!RuntimeAgent.CallArgument&} */ (InjectedScriptHost.eval(args));
for (var i = 0; i & callArgs. ++i) {
resolvedArgs[i] = this._resolveCallArgument(callArgs[i]);
} catch (e) {
return toString(e);
var objectGroup = this._idToObjectGroupName[parsedObjectId.id];
var func = InjectedScriptHost.eval(&(& + expression + &)&);
if (typeof func !== &function&)
return &Given expression does not evaluate to a function&;
return { wasThrown: false,
result: this._wrapObject(InjectedScriptHost.callFunction(func, object, resolvedArgs), objectGroup, returnByValue),
__proto__: null };
} catch (e) {
return this._createThrownValue(e, objectGroup, false);
* Resolves a value from CallArgument description.
* @param {!RuntimeAgent.CallArgument} callArgumentJson
* @return {*} resolved value
* @throws {string} error message
_resolveCallArgument: function(callArgumentJson)
callArgumentJson = nullifyObjectProto(callArgumentJson);
var objectId = callArgumentJson.objectId;
if (objectId) {
var parsedArgId = this._parseObjectId(objectId);
if (!parsedArgId || parsedArgId[&injectedScriptId&] !== injectedScriptId)
throw &Arguments should belong to the same JavaScript world as the target object.&;
var resolvedArg = this._objectForId(parsedArgId);
if (!this._isDefined(resolvedArg))
throw &Could not find object with given id&;
return resolvedA
} else if (&value& in callArgumentJson) {
var value = callArgumentJson.
if (callArgumentJson.type === &number& && typeof value !== &number&)
value = Number(value);
* @param {?JavaScriptCallFrame} callFrame
* @param {string} expression
* @param {string} objectGroup
* @param {boolean} injectCommandLineAPI
* @param {boolean} returnByValue
* @param {boolean} generatePreview
* @param {!Array.&!Object&=} scopeChain
* @return {!Object}
_evaluateAndWrap: function(callFrame, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, scopeChain)
var wrappedResult = this._evaluateOn(callFrame, objectGroup, expression, injectCommandLineAPI, scopeChain);
if (!wrappedResult.exceptionDetails) {
return { wasThrown: false,
result: this._wrapObject(wrappedResult.result, objectGroup, returnByValue, generatePreview),
__proto__: null };
return this._createThrownValue(wrappedResult.result, objectGroup, generatePreview, wrappedResult.exceptionDetails);
* @param {*} value
* @param {string} objectGroup
* @param {boolean} generatePreview
* @param {!DebuggerAgent.ExceptionDetails=} exceptionDetails
* @return {!Object}
_createThrownValue: function(value, objectGroup, generatePreview, exceptionDetails)
var remoteObject = this._wrapObject(value, objectGroup, false, generatePreview && InjectedScriptHost.subtype(value) !== &error&);
if (!remoteObject.description){
remoteObject.description = toStringDescription(value);
} catch (e) {}
return { wasThrown: true, result: remoteObject, exceptionDetails: exceptionDetails, __proto__: null };
* @param {?JavaScriptCallFrame} callFrame
* @param {string} objectGroup
* @param {string} expression
* @param {boolean} injectCommandLineAPI
* @param {!Array.&!Object&=} scopeChain
* @return {*}
_evaluateOn: function(callFrame, objectGroup, expression, injectCommandLineAPI, scopeChain)
// Only install command line api object for the time of evaluation.
// Surround the expression in with statements to inject our command line API so that
// the window object properties still take more precedent than our API functions.
var scopeExtensionForEval = (callFrame && injectCommandLineAPI) ? new CommandLineAPI(this._commandLineAPIImpl, callFrame) :
injectCommandLineAPI = !scopeExtensionForEval && !callFrame && injectCommandLineAPI && !(&__commandLineAPI& in inspectedWindow);
var injectScopeChain = scopeChain && scopeChain.length && !(&__scopeChainForEval& in inspectedWindow);
var prefix = &&;
var suffix = &&;
if (injectCommandLineAPI) {
InjectedScriptHost.setNonEnumProperty(inspectedWindow, &__commandLineAPI&, new CommandLineAPI(this._commandLineAPIImpl, callFrame));
prefix = &with (typeof __commandLineAPI !== &#39;undefined&#39; ? __commandLineAPI : { __proto__: null }) {&;
suffix = &}&;
if (injectScopeChain) {
InjectedScriptHost.setNonEnumProperty(inspectedWindow, &__scopeChainForEval&, scopeChain);
for (var i = 0; i & scopeChain. ++i) {
prefix = &with (typeof __scopeChainForEval !== &#39;undefined&#39; ? __scopeChainForEval[& + i + &] : { __proto__: null }) {& + (suffix ? & & : &&) +
if (suffix)
suffix += & }&;
suffix = &}&;
if (prefix)
expression = prefix + &\n& + expression + &\n& +
var wrappedResult = callFrame ? callFrame.evaluateWithExceptionDetails(expression, scopeExtensionForEval) : InjectedScriptHost.evaluateWithExceptionDetails(expression);
if (objectGroup === &console& && !wrappedResult.exceptionDetails)
this._lastResult = wrappedResult.
return wrappedR
} finally {
if (injectCommandLineAPI)
delete inspectedWindow[&__commandLineAPI&];
if (injectScopeChain)
delete inspectedWindow[&__scopeChainForEval&];
* @param {?Object} callFrame
* @param {number} asyncOrdinal
* @return {!Array.&!InjectedScript.CallFrameProxy&|boolean}
wrapCallFrames: function(callFrame, asyncOrdinal)
if (!callFrame)
var result = [];
var depth = 0;
result[depth] = new InjectedScript.CallFrameProxy(depth, callFrame, asyncOrdinal);
callFrame = callFrame.
} while (callFrame);
* @param {!JavaScriptCallFrame} topCallFrame
* @param {!Array.&!JavaScriptCallFrame&} asyncCallStacks
* @param {string} callFrameId
* @param {string} expression
* @param {string} objectGroup
* @param {boolean} injectCommandLineAPI
* @param {boolean} returnByValue
* @param {boolean} generatePreview
* @return {*}
evaluateOnCallFrame: function(topCallFrame, asyncCallStacks, callFrameId, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview)
var parsedCallFrameId = nullifyObjectProto(/** @type {!Object} */ (InjectedScriptHost.eval(&(& + callFrameId + &)&)));
var callFrame = this._callFrameForParsedId(topCallFrame, parsedCallFrameId, asyncCallStacks);
if (!callFrame)
return &Could not find call frame with given id&;
if (parsedCallFrameId[&asyncOrdinal&])
return this._evaluateAndWrap(null, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview, callFrame.scopeChain);
return this._evaluateAndWrap(callFrame, expression, objectGroup, injectCommandLineAPI, returnByValue, generatePreview);
* @param {!JavaScriptCallFrame} topCallFrame
* @param {string} callFrameId
* @return {*}
restartFrame: function(topCallFrame, callFrameId)
var callFrame = this._callFrameForId(topCallFrame, callFrameId);
if (!callFrame)
return &Could not find call frame with given id&;
var result = callFrame.restart();
if (result === false)
result = &Restart frame is not supported&;
* @param {!JavaScriptCallFrame} topCallFrame
* @param {string} callFrameId
* @return {*} a stepIn position array ready for protocol JSON or a string error
getStepInPositions: function(topCallFrame, callFrameId)
var callFrame = this._callFrameForId(topCallFrame, callFrameId);
if (!callFrame)
return &Could not find call frame with given id&;
var stepInPositionsUnpacked = JSON.parse(callFrame.stepInPositions);
if (typeof stepInPositionsUnpacked !== &object&)
return &Step in positions not available&;
return stepInPositionsU
* Either callFrameId or functionObjectId must be specified.
* @param {!JavaScriptCallFrame} topCallFrame
* @param {string|boolean} callFrameId or false
* @param {string|boolean} functionObjectId or false
* @param {number} scopeNumber
* @param {string} variableName
* @param {string} newValueJsonString RuntimeAgent.CallArgument structure serialized as string
* @return {string|undefined} undefined if success or an error message
setVariableValue: function(topCallFrame, callFrameId, functionObjectId, scopeNumber, variableName, newValueJsonString)
var newValueJson = /** @type {!RuntimeAgent.CallArgument} */ (InjectedScriptHost.eval(&(& + newValueJsonString + &)&));
var resolvedValue = this._resolveCallArgument(newValueJson);
if (typeof callFrameId === &string&) {
var callFrame = this._callFrameForId(topCallFrame, callFrameId);
if (!callFrame)
return &Could not find call frame with given id&;
callFrame.setVariableValue(scopeNumber, variableName, resolvedValue)
var parsedFunctionId = this._parseObjectId(/** @type {string} */ (functionObjectId));
var func = this._objectForId(parsedFunctionId);
if (typeof func !== &function&)
return &Could not resolve function by id&;
InjectedScriptHost.setFunctionVariableValue(func, scopeNumber, variableName, resolvedValue);
} catch (e) {
return toString(e);
* @param {!JavaScriptCallFrame} topCallFrame
* @param {string} callFrameId
* @return {?JavaScriptCallFrame}
_callFrameForId: function(topCallFrame, callFrameId)
var parsedCallFrameId = nullifyObjectProto(/** @type {!Object} */ (InjectedScriptHost.eval(&(& + callFrameId + &)&)));
return this._callFrameForParsedId(topCallFrame, parsedCallFrameId, []);
* @param {!JavaScriptCallFrame} topCallFrame
* @param {!Object} parsedCallFrameId
* @param {!Array.&!JavaScriptCallFrame&} asyncCallStacks
* @return {?JavaScriptCallFrame}
_callFrameForParsedId: function(topCallFrame, parsedCallFrameId, asyncCallStacks)
var asyncOrdinal = parsedCallFrameId[&asyncOrdinal&]; // 1-based index
if (asyncOrdinal)
topCallFrame = asyncCallStacks[asyncOrdinal - 1];
var ordinal = parsedCallFrameId[&ordinal&];
var callFrame = topCallF
while (--ordinal &= 0 && callFrame)
callFrame = callFrame.
return callF
* @param {!Object} objectId
* @return {!Object|symbol}
_objectForId: function(objectId)
return this._idToWrappedObject[objectId.id];
* @param {string} objectId
* @return {!Object|symbol}
findObjectById: function(objectId)
var parsedObjectId = this._parseObjectId(objectId);
return this._objectForId(parsedObjectId);
* @param {string} objectId
* @return {?Node}
nodeForObjectId: function(objectId)
var object = this.findObjectById(objectId);
if (!object || this._subtype(object) !== &node&)
return /** @type {!Node} */ (object);
* @param {string} name
* @return {!Object}
module: function(name)
return this._modules[name];
* @param {string} name
* @param {string} source
* @return {?Object}
injectModule: function(name, source)
delete this._modules[name];
var moduleFunction = InjectedScriptHost.eval(&(& + source + &)&);
if (typeof moduleFunction !== &function&) {
inspectedWindow.console.error(&Web Inspector error: A function was expected for module %s evaluation&, name);
var module = /** @type {!Object} */ (InjectedScriptHost.callFunction(moduleFunction, inspectedWindow, [InjectedScriptHost, inspectedWindow, injectedScriptId, this]));
this._modules[name] =
* @param {*} object
* @return {boolean}
_isDefined: function(object)
return !!object || this._isHTMLAllCollection(object);
* @param {*} object
* @return {boolean}
_isHTMLAllCollection: function(object)
// document.all is reported as undefined, but we still want to process it.
return (typeof object === &undefined&) && InjectedScriptHost.isHTMLAllCollection(object);
* @param {*} obj
* @return {?string}
_subtype: function(obj)
if (obj === null)
return &null&;
if (this.isPrimitiveValue(obj))
var subtype = InjectedScriptHost.subtype(obj);
// FIXME: Consider exposing &error& subtype via protocol.
if (subtype && subtype !== &error&)
if (isArrayLike(obj))
return &array&;
// If owning frame has navigated to somewhere else window properties will be undefined.
* @param {*} obj
* @return {?string}
_describe: function(obj)
if (this.isPrimitiveValue(obj))
var subtype = this._subtype(obj);
if (subtype === &regexp&)
return toString(obj);
if (subtype === &date&)
return toString(obj);
if (subtype === &node&) {
var description = obj.nodeName.toLowerCase();
switch (obj.nodeType) {
case 1 /* Node.ELEMENT_NODE */:
description += obj.id ? &#& + obj.id : &&;
var className = obj.classN
description += (className && typeof className === &string&) ? &.& + className.trim().replace(/\s+/g, &.&) : &&;
case 10 /*Node.DOCUMENT_TYPE_NODE */:
description = &&!DOCTYPE & + description + &&&;
var className = InjectedScriptHost.internalConstructorName(obj);
if (subtype === &array&) {
if (typeof obj.length === &number&)
className += &[& + obj.length + &]&;
return classN
// NodeList in JSC is a function, check for array prior to this.
if (typeof obj === &function&)
return toString(obj);
if (isSymbol(obj)) {
return /** @type {string} */ (InjectedScriptHost.callFunction(Symbol.prototype.toString, obj)) || &Symbol&;
} catch (e) {
return &Symbol&;
if (InjectedScriptHost.subtype(obj) === &error&) {
var message = obj.
if (message)
return className + &: & +
} catch(e) {
return classN
* @type {!InjectedScript}
var injectedScript = new InjectedScript();
* @constructor
* @param {*} object
* @param {string=} objectGroupName
* @param {boolean=} forceValueType
* @param {boolean=} generatePreview
* @param {?Array.&string&=} columnNames
* @param {boolean=} isTable
* @param {boolean=} skipEntriesPreview
InjectedScript.RemoteObject = function(object, objectGroupName, forceValueType, generatePreview, columnNames, isTable, skipEntriesPreview)
this.type =
if (this.type === &undefined& && injectedScript._isHTMLAllCollection(object))
this.type = &object&;
if (injectedScript.isPrimitiveValue(object) || object === null || forceValueType) {
// We don&#39;t send undefined values over JSON.
if (this.type !== &undefined&)
this.value =
// Null object is object with &#39;null&#39; subtype.
if (object === null)
this.subtype = &null&;
// Provide user-friendly number values.
if (this.type === &number&) {
this.description = toStringDescription(object);
// Override &value& property for values that can not be JSON-stringified.
switch (this.description) {
case &NaN&:
case &Infinity&:
case &-Infinity&:
case &-0&:
this.value = this.
object = /** @type {!Object} */ (object);
this.objectId = injectedScript._bind(object, objectGroupName);
var subtype = injectedScript._subtype(object);
if (subtype)
this.subtype =
var className = InjectedScriptHost.internalConstructorName(object);
if (className)
this.className = classN
this.description = injectedScript._describe(object);
if (generatePreview && this.type === &object&)
this.preview = this._generatePreview(object, undefined, columnNames, isTable, skipEntriesPreview);
InjectedScript.RemoteObject.prototype = {
* @return {!RuntimeAgent.ObjectPreview} preview
_createEmptyPreview: function()
var preview = {
type: /** @type {!RuntimeAgent.ObjectPreviewType.&string&} */ (this.type),
description: this.description || toStringDescription(this.value),
lossless: true,
overflow: false,
properties: [],
__proto__: null
if (this.subtype)
preview.subtype = /** @type {!RuntimeAgent.ObjectPreviewSubtype.&string&} */ (this.subtype);
* @param {!Object} object
* @param {?Array.&string&=} firstLevelKeys
* @param {?Array.&string&=} secondLevelKeys
* @param {boolean=} isTable
* @param {boolean=} skipEntriesPreview
* @return {!RuntimeAgent.ObjectPreview} preview
_generatePreview: function(object, firstLevelKeys, secondLevelKeys, isTable, skipEntriesPreview)
var preview = this._createEmptyPreview();
var firstLevelKeysCount = firstLevelKeys ? firstLevelKeys.length : 0;
var propertiesThreshold = {
properties: isTable ? 1000 : max(5, firstLevelKeysCount),
indexes: isTable ? 1000 : max(100, firstLevelKeysCount),
__proto__: null
var descriptors = injectedScript._propertyDescriptors(object);
if (firstLevelKeys) {
var nameToDescriptors = { __proto__: null };
for (var i = 0; i & descriptors. ++i) {
var descriptor = descriptors[i];
nameToDescriptors[&#& + descriptor.name] =
descriptors = [];
for (var i = 0; i & firstLevelKeys. ++i)
descriptors[i] = nameToDescriptors[&#& + firstLevelKeys[i]];
this._appendPropertyDescriptors(preview, descriptors, propertiesThreshold, secondLevelKeys, isTable);
if (propertiesThreshold.indexes & 0 || propertiesThreshold.properties & 0)
// Add internal properties to preview.
var internalProperties = InjectedScriptHost.getInternalProperties(object) || [];
for (var i = 0; i & internalProperties. ++i) {
internalProperties[i] = nullifyObjectProto(internalProperties[i]);
internalProperties[i].enumerable =
this._appendPropertyDescriptors(preview, internalProperties, propertiesThreshold, secondLevelKeys, isTable);
if (this.subtype === &map& || this.subtype === &set&)
this._appendEntriesPreview(object, preview, skipEntriesPreview);
} catch (e) {
preview.lossless =
* @param {!RuntimeAgent.ObjectPreview} preview
* @param {!Array.&!Object&} descriptors
* @param {!Object} propertiesThreshold
* @param {?Array.&string&=} secondLevelKeys
* @param {boolean=} isTable
_appendPropertyDescriptors: function(preview, descriptors, propertiesThreshold, secondLevelKeys, isTable)
for (var i = 0; i & descriptors. ++i) {
if (propertiesThreshold.indexes & 0 || propertiesThreshold.properties & 0)
var descriptor = descriptors[i];
if (!descriptor)
if (descriptor.wasThrown) {
preview.lossless =
if (!descriptor.enumerable && !descriptor.isOwn)
var name = descriptor.
if (name === &__proto__&)
if (this.subtype === &array& && name === &length&)
if (!(&value& in descriptor)) {
preview.lossless =
this._appendPropertyPreview(preview, { name: name, type: &accessor&, __proto__: null }, propertiesThreshold);
var value = descriptor.
if (value === null) {
this._appendPropertyPreview(preview, { name: name, type: &object&, subtype: &null&, value: &null&, __proto__: null }, propertiesThreshold);
var type =
if (!descriptor.enumerable && type === &function&)
if (type === &undefined& && injectedScript._isHTMLAllCollection(value))
type = &object&;
var maxLength = 100;
if (InjectedScript.primitiveTypes[type]) {
if (type === &string& && value.length & maxLength) {
value = this._abbreviateString(value, maxLength, true);
preview.lossless =
this._appendPropertyPreview(preview, { name: name, type: type, value: toStringDescription(value), __proto__: null }, propertiesThreshold);
var property = { name: name, type: type, __proto__: null };
var subtype = injectedScript._subtype(value);
if (subtype)
property.subtype =
if (secondLevelKeys === null || secondLevelKeys) {
var subPreview = this._generatePreview(value, secondLevelKeys || undefined, undefined, isTable);
property.valuePreview = subP
if (!subPreview.lossless)
preview.lossless =
if (subPreview.overflow)
preview.overflow =
var description = &&;
if (type !== &function&)
description = this._abbreviateString(/** @type {string} */ (injectedScript._describe(value)), maxLength, subtype === &regexp&);
property.value =
preview.lossless =
this._appendPropertyPreview(preview, property, propertiesThreshold);
* @param {!RuntimeAgent.ObjectPreview} preview
* @param {!Object} property
* @param {!Object} propertiesThreshold
_appendPropertyPreview: function(preview, property, propertiesThreshold)
if (toString(property.name &&& 0) === property.name)
propertiesThreshold.indexes--;
propertiesThreshold.properties--;
if (propertiesThreshold.indexes & 0 || propertiesThreshold.properties & 0) {
preview.overflow =
preview.lossless =
push(preview.properties, property);
* @param {!Object} object
* @param {!RuntimeAgent.ObjectPreview} preview
* @param {boolean=} skipEntriesPreview
_appendEntriesPreview: function(object, preview, skipEntriesPreview)
var entries = InjectedScriptHost.collectionEntries(object);
if (!entries)
if (skipEntriesPreview) {
if (entries.length) {
preview.overflow =
preview.lossless =
preview.entries = [];
var entriesThreshold = 5;
for (var i = 0; i & entries. ++i) {
if (preview.entries.length &= entriesThreshold) {
preview.overflow =
preview.lossless =
var entry = nullifyObjectProto(entries[i]);
var previewEntry = {
value: generateValuePreview(entry.value),
__proto__: null
if (&key& in entry)
previewEntry.key = generateValuePreview(entry.key);
push(preview.entries, previewEntry);
* @param {*} value
* @return {!RuntimeAgent.ObjectPreview}
function generateValuePreview(value)
var remoteObject = new InjectedScript.RemoteObject(value, undefined, undefined, true, undefined, undefined, true);
var valuePreview = remoteObject.preview || remoteObject._createEmptyPreview();
if (remoteObject.objectId)
injectedScript.releaseObject(remoteObject.objectId);
if (!valuePreview.lossless)
preview.lossless =
return valueP
* @param {string} string
* @param {number} maxLength
* @param {boolean=} middle
* @return {string}
_abbreviateString: function(string, maxLength, middle)
if (string.length &= maxLength)
if (middle) {
var leftHalf = maxLength && 1;
var rightHalf = maxLength - leftHalf - 1;
return string.substr(0, leftHalf) + &\u2026& + string.substr(string.length - rightHalf, rightHalf);
return string.substr(0, maxLength) + &\u2026&;
__proto__: null
* @constructor
* @param {number} ordinal
* @param {!JavaScriptCallFrame} callFrame
* @param {number} asyncOrdinal
InjectedScript.CallFrameProxy = function(ordinal, callFrame, asyncOrdinal)
this.callFrameId = &{\&ordinal\&:& + ordinal + &,\&injectedScriptId\&:& + injectedScriptId + (asyncOrdinal ? &,\&asyncOrdinal\&:& + asyncOrdinal : &&) + &}&;
this.functionName = (callFrame.type === &function& ? callFrame.functionName : &&);
this.location = { scriptId: toString(callFrame.sourceID), lineNumber: callFrame.line, columnNumber: callFrame.column, __proto__: null };
this.scopeChain = this._wrapScopeChain(callFrame);
this.this = injectedScript._wrapObject(callFrame.thisObject, &backtrace&);
if (callFrame.isAtReturn)
this.returnValue = injectedScript._wrapObject(callFrame.returnValue, &backtrace&);
InjectedScript.CallFrameProxy.prototype = {
* @param {!JavaScriptCallFrame} callFrame
* @return {!Array.&!DebuggerAgent.Scope&}
_wrapScopeChain: function(callFrame)
var scopeChain = callFrame.scopeC
var scopeChainProxy = [];
for (var i = 0; i & scopeChain. ++i)
scopeChainProxy[i] = InjectedScript.CallFrameProxy._createScopeJson(callFrame.scopeType(i), scopeChain[i], &backtrace&);
return scopeChainP
__proto__: null
* @param {number} scopeTypeCode
* @param {*} scopeObject
* @param {string} groupId
* @return {!DebuggerAgent.Scope}
InjectedScript.CallFrameProxy._createScopeJson = function(scopeTypeCode, scopeObject, groupId)
const GLOBAL_SCOPE = 0;
const LOCAL_SCOPE = 1;
const WITH_SCOPE = 2;
const CLOSURE_SCOPE = 3;
const CATCH_SCOPE = 4;
/** @type {!Object.&number, string&} */
var scopeTypeNames = { __proto__: null };
scopeTypeNames[GLOBAL_SCOPE] = &global&;
scopeTypeNames[LOCAL_SCOPE] = &local&;
scopeTypeNames[WITH_SCOPE] = &with&;
scopeTypeNames[CLOSURE_SCOPE] = &closure&;
scopeTypeNames[CATCH_SCOPE] = &catch&;
object: injectedScript._wrapObject(scopeObject, groupId),
type: /** @type {!DebuggerAgent.ScopeType} */ (scopeTypeNames[scopeTypeCode]),
__proto__: null
* @constructor
* @param {!CommandLineAPIImpl} commandLineAPIImpl
* @param {?JavaScriptCallFrame} callFrame
function CommandLineAPI(commandLineAPIImpl, callFrame)
* @param {string} member
* @return {boolean}
function inScopeVariables(member)
if (!callFrame)
return (member in inspectedWindow);
var scopeChain = callFrame.scopeC
for (var i = 0; i & scopeChain. ++i) {
if (member in scopeChain[i])
* @param {string} name The name of the method for which a toString method should be generated.
* @return {function():string}
function customToStringMethod(name)
return function()
var funcArgsSyntax = &&;
var funcSyntax = && + commandLineAPIImpl[name];
funcSyntax = funcSyntax.replace(/\n/g, & &);
funcSyntax = funcSyntax.replace(/^function[^\(]*\(([^\)]*)\).*$/, &$1&);
funcSyntax = funcSyntax.replace(/\s*,\s*/g, &, &);
funcSyntax = funcSyntax.replace(/\bopt_(\w+)\b/g, &[$1]&);
funcArgsSyntax = funcSyntax.trim();
} catch (e) {
return &function & + name + &(& + funcArgsSyntax + &) { [Command Line API] }&;
for (var i = 0; i & CommandLineAPI.members_. ++i) {
var member = CommandLineAPI.members_[i];
if (inScopeVariables(member))
this[member] = bind(commandLineAPIImpl[member], commandLineAPIImpl);
this[member].toString = customToStringMethod(member);
for (var i = 0; i & 5; ++i) {
var member = &$& +
if (inScopeVariables(member))
this.__defineGetter__(&$& + i, bind(commandLineAPIImpl._inspectedObject, commandLineAPIImpl, i));
this.$_ = injectedScript._lastR
this.__proto__ =
// NOTE: Please keep the list of API methods below snchronized to that in WebInspector.RuntimeModel!
// NOTE: Argument names of these methods will be printed in the console, so use pretty names!
* @type {!Array.&string&}
CommandLineAPI.members_ = [
&$&, &$$&, &$x&, &dir&, &dirxml&, &keys&, &values&, &profile&, &profileEnd&,
&monitorEvents&, &unmonitorEvents&, &inspect&, &copy&, &clear&, &getEventListeners&,
&debug&, &undebug&, &monitor&, &unmonitor&, &table&
* @constructor
function CommandLineAPIImpl()
CommandLineAPIImpl.prototype = {
* @param {string} selector
* @param {!Node=} opt_startNode
* @return {*}
$: function (selector, opt_startNode)
if (this._canQuerySelectorOnNode(opt_startNode))
return opt_startNode.querySelector(selector);
return inspectedWindow.document.querySelector(selector);
* @param {string} selector
* @param {!Node=} opt_startNode
* @return {*}
$$: function (selector, opt_startNode)
if (this._canQuerySelectorOnNode(opt_startNode))
return opt_startNode.querySelectorAll(selector);
return inspectedWindow.document.querySelectorAll(selector);
* @param {!Node=} node
* @return {boolean}
_canQuerySelectorOnNode: function(node)
return !!node && InjectedScriptHost.subtype(node) === &node& && (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.DOCUMENT_NODE || node.nodeType === Node.DOCUMENT_FRAGMENT_NODE);
* @param {string} xpath
* @param {!Node=} opt_startNode
* @return {*}
$x: function(xpath, opt_startNode)
var doc = (opt_startNode && opt_startNode.ownerDocument) || inspectedWindow.
var result = doc.evaluate(xpath, opt_startNode || doc, null, XPathResult.ANY_TYPE, null);
switch (result.resultType) {
case XPathResult.NUMBER_TYPE:
return result.numberV
case XPathResult.STRING_TYPE:
return result.stringV
case XPathResult.BOOLEAN_TYPE:
return result.booleanV
var nodes = [];
while (node = result.iterateNext())
push(nodes, node);
* @return {*}
dir: function(var_args)
return InjectedScriptHost.callFunction(inspectedWindow.console.dir, inspectedWindow.console, slice(arguments));
* @return {*}
dirxml: function(var_args)
return InjectedScriptHost.callFunction(inspectedWindow.console.dirxml, inspectedWindow.console, slice(arguments));
* @return {!Array.&string&}
keys: function(object)
return Object.keys(object);
* @return {!Array.&*&}
values: function(object)
var result = [];
for (var key in object)
push(result, object[key]);
* @return {*}
profile: function(opt_title)
return InjectedScriptHost.callFunction(inspectedWindow.console.profile, inspectedWindow.console, slice(arguments));
* @return {*}
profileEnd: function(opt_title)
return InjectedScriptHost.callFunction(inspectedWindow.console.profileEnd, inspectedWindow.console, slice(arguments));
* @param {!Object} object
* @param {!Array.&string&|string=} opt_types
monitorEvents: function(object, opt_types)
if (!object || !object.addEventListener || !object.removeEventListener)
var types = this._normalizeEventTypes(opt_types);
for (var i = 0; i & types. ++i) {
object.removeEventListener(types[i], this._logEvent, false);
object.addEventListener(types[i], this._logEvent, false);
* @param {!Object} object
* @param {!Array.&string&|string=} opt_types
unmonitorEvents: function(object, opt_types)
if (!object || !object.addEventListener || !object.removeEventListener)
var types = this._normalizeEventTypes(opt_types);
for (var i = 0; i & types. ++i)
object.removeEventListener(types[i], this._logEvent, false);
* @param {*} object
* @return {*}
inspect: function(object)
return injectedScript._inspect(object);
copy: function(object)
if (injectedScript._subtype(object) === &node&) {
string = object.outerHTML;
} else if (injectedScript.isPrimitiveValue(object)) {
string = toString(object);
string = JSON.stringify(object, null, &
} catch (e) {
string = toString(object);
var hints = { copyToClipboard: true, __proto__: null };
var remoteObject = injectedScript._wrapObject(string, &&)
InjectedScriptHost.inspect(remoteObject, hints);
clear: function()
InjectedScriptHost.clearConsoleMessages();
* @param {!Node} node
* @return {!Array.&!{type: string, listener: function(), useCapture: boolean, remove: function()}&|undefined}
getEventListeners: function(node)
var result = nullifyObjectProto(InjectedScriptHost.getEventListeners(node));
if (!result)
/** @this {{type: string, listener: function(), useCapture: boolean}} */
var removeFunc = function()
node.removeEventListener(this.type, this.listener, this.useCapture);
for (var type in result) {
var listeners = result[type];
for (var i = 0, listener = listeners[i]; ++i) {
listener[&type&] =
listener[&remove&] = removeF
debug: function(fn)
InjectedScriptHost.debugFunction(fn);
undebug: function(fn)
InjectedScriptHost.undebugFunction(fn);
monitor: function(fn)
InjectedScriptHost.monitorFunction(fn);
unmonitor: function(fn)
InjectedScriptHost.unmonitorFunction(fn);
table: function(data, opt_columns)
InjectedScriptHost.callFunction(inspectedWindow.console.table, inspectedWindow.console, slice(arguments));
* @param {number} num
_inspectedObject: function(num)
return InjectedScriptHost.inspectedObject(num);
* @param {!Array.&string&|string=} types
* @return {!Array.&string&}
_normalizeEventTypes: function(types)
if (typeof types === &undefined&)
types = [&mouse&, &key&, &touch&, &control&, &load&, &unload&, &abort&, &error&, &select&, &change&, &submit&, &reset&, &focus&, &blur&, &resize&, &scroll&, &search&, &devicemotion&, &deviceorientation&];
else if (typeof types === &string&)
types = [types];
var result = [];
for (var i = 0; i & types. ++i) {
if (types[i] === &mouse&)
push(result, &mousedown&, &mouseup&, &click&, &dblclick&, &mousemove&, &mouseover&, &mouseout&, &mousewheel&);
else if (types[i] === &key&)
push(result, &keydown&, &keyup&, &keypress&, &textInput&);
else if (types[i] === &touch&)
push(result, &touchstart&, &touchmove&, &touchend&, &touchcancel&);
else if (types[i] === &control&)
push(result, &resize&, &scroll&, &zoom&, &focus&, &blur&, &select&, &change&, &submit&, &reset&);
push(result, types[i]);
* @param {!Event} event
_logEvent: function(event)
inspectedWindow.console.log(event.type, event);
injectedScript._commandLineAPIImpl = new CommandLineAPIImpl();
return injectedS
可以看看,代码还是很不错的!
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1172201次
积分:13940
积分:13940
排名:第601名
原创:280篇
转载:346篇
评论:133条
(2)(2)(1)(7)(11)(8)(7)(1)(4)(3)(6)(16)(13)(3)(12)(13)(52)(12)(20)(6)(18)(45)(13)(28)(4)(15)(7)(42)(26)(13)(24)(36)(22)(10)(9)(5)(17)(7)(11)(26)(10)(13)(15)(10)}

我要回帖

更多关于 ie图标删不掉 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信