InspectorOverlayPage.html 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. <!--
  2. Copyright (C) 2012 Google Inc. All rights reserved.
  3. Redistribution and use in source and binary forms, with or without
  4. modification, are permitted provided that the following conditions
  5. are met:
  6. 1. Redistributions of source code must retain the above copyright
  7. notice, this list of conditions and the following disclaimer.
  8. 2. Redistributions in binary form must reproduce the above copyright
  9. notice, this list of conditions and the following disclaimer in the
  10. documentation and/or other materials provided with the distribution.
  11. 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
  12. its contributors may be used to endorse or promote products derived
  13. from this software without specific prior written permission.
  14. THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  15. EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  18. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  21. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  23. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. -->
  25. <!DOCTYPE html>
  26. <html>
  27. <head>
  28. <style>
  29. body {
  30. margin: 0;
  31. padding: 0;
  32. }
  33. body.platform-mac {
  34. font-size: 11px;
  35. font-family: Menlo, Monaco;
  36. }
  37. body.platform-windows {
  38. font-size: 12px;
  39. font-family: Consolas, Lucida Console;
  40. }
  41. body.platform-linux {
  42. font-size: 11px;
  43. font-family: dejavu sans mono;
  44. }
  45. .fill {
  46. position: absolute;
  47. top: 0;
  48. right: 0;
  49. bottom: 0;
  50. left: 0;
  51. }
  52. .dimmed {
  53. background-color: rgba(0, 0, 0, 0.31);
  54. }
  55. .message-line {
  56. margin: 10px 0;
  57. text-align: center;
  58. }
  59. .message-box {
  60. background-color: rgb(255, 255, 194);
  61. border: 1px solid rgb(128, 128, 128);
  62. display: inline-block;
  63. padding: 2px 4px;
  64. }
  65. .px {
  66. color: rgb(128, 128, 128);
  67. }
  68. #element-title {
  69. position: absolute;
  70. z-index: 10;
  71. }
  72. #tag-name {
  73. /* Keep this in sync with view-source.css (.webkit-html-tag-name) */
  74. color: rgb(136, 18, 128);
  75. }
  76. #node-id {
  77. /* Keep this in sync with view-source.css (.webkit-html-attribute-value) */
  78. color: rgb(26, 26, 166);
  79. }
  80. #class-name {
  81. /* Keep this in sync with view-source.css (.webkit-html-attribute-name) */
  82. color: rgb(153, 69, 0);
  83. }
  84. #right-gutter {
  85. display: none;
  86. right: 0;
  87. top: 0;
  88. bottom: 0;
  89. position: absolute;
  90. background-color: darkgray;
  91. }
  92. #bottom-gutter {
  93. display: none;
  94. left: 0;
  95. right: 0;
  96. bottom: 0;
  97. position: absolute;
  98. background-color: darkgray;
  99. }
  100. </style>
  101. <script>
  102. const lightGridColor = "rgba(0,0,0,0.2)";
  103. const darkGridColor = "rgba(0,0,0,0.5)";
  104. const transparentColor = "rgba(0, 0, 0, 0)";
  105. const gridBackgroundColor = "rgba(255, 255, 255, 0.6)";
  106. function drawPausedInDebuggerMessage(message)
  107. {
  108. var pausedInDebugger = document.getElementById("paused-in-debugger");
  109. pausedInDebugger.textContent = message;
  110. pausedInDebugger.style.visibility = "visible";
  111. document.body.classList.add("dimmed");
  112. }
  113. function _drawGrid(highlight, rulerAtRight, rulerAtBottom)
  114. {
  115. if (!highlight.showRulers)
  116. return;
  117. context.save();
  118. var width = canvas.width;
  119. var height = canvas.height;
  120. const gridSubStep = 5;
  121. const gridStep = 50;
  122. {
  123. // Draw X grid background
  124. context.save();
  125. context.fillStyle = gridBackgroundColor;
  126. if (rulerAtBottom)
  127. context.fillRect(0, height - 15, width, height);
  128. else
  129. context.fillRect(0, 0, width, 15);
  130. // Clip out backgrounds intersection
  131. context.globalCompositeOperation = "destination-out";
  132. context.fillStyle = "red";
  133. if (rulerAtRight)
  134. context.fillRect(width - 15, 0, width, height);
  135. else
  136. context.fillRect(0, 0, 15, height);
  137. context.restore();
  138. // Draw Y grid background
  139. context.fillStyle = gridBackgroundColor;
  140. if (rulerAtRight)
  141. context.fillRect(width - 15, 0, width, height);
  142. else
  143. context.fillRect(0, 0, 15, height);
  144. }
  145. context.lineWidth = 1;
  146. context.strokeStyle = darkGridColor;
  147. context.fillStyle = darkGridColor;
  148. {
  149. // Draw labels.
  150. context.save();
  151. context.translate(-highlight.scrollX, 0.5 - highlight.scrollY);
  152. for (var y = 2 * gridStep; y < height + highlight.scrollY; y += 2 * gridStep) {
  153. context.save();
  154. context.translate(highlight.scrollX, y);
  155. context.rotate(-Math.PI / 2);
  156. context.fillText(y, 2, rulerAtRight ? width - 7 : 13);
  157. context.restore();
  158. }
  159. context.translate(0.5, -0.5);
  160. for (var x = 2 * gridStep; x < width + highlight.scrollX; x += 2 * gridStep) {
  161. context.save();
  162. context.fillText(x, x + 2, rulerAtBottom ? highlight.scrollY + height - 7 : highlight.scrollY + 13);
  163. context.restore();
  164. }
  165. context.restore();
  166. }
  167. {
  168. // Draw vertical grid
  169. context.save();
  170. if (rulerAtRight) {
  171. context.translate(width, 0);
  172. context.scale(-1, 1);
  173. }
  174. context.translate(-highlight.scrollX, 0.5 - highlight.scrollY);
  175. for (var y = gridStep; y < height + highlight.scrollY; y += gridStep) {
  176. context.beginPath();
  177. context.moveTo(highlight.scrollX, y);
  178. var markLength = (y % (gridStep * 2)) ? 5 : 8;
  179. context.lineTo(highlight.scrollX + markLength, y);
  180. context.stroke();
  181. }
  182. context.strokeStyle = lightGridColor;
  183. for (var y = gridSubStep; y < highlight.scrollY + height; y += gridSubStep) {
  184. if (!(y % gridStep))
  185. continue;
  186. context.beginPath();
  187. context.moveTo(highlight.scrollX, y);
  188. context.lineTo(highlight.scrollX + gridSubStep, y);
  189. context.stroke();
  190. }
  191. context.restore();
  192. }
  193. {
  194. // Draw horizontal grid
  195. context.save();
  196. if (rulerAtBottom) {
  197. context.translate(0, height);
  198. context.scale(1, -1);
  199. }
  200. context.translate(0.5 - highlight.scrollX, -highlight.scrollY);
  201. for (var x = gridStep; x < width + highlight.scrollX; x += gridStep) {
  202. context.beginPath();
  203. context.moveTo(x, highlight.scrollY);
  204. var markLength = (x % (gridStep * 2)) ? 5 : 8;
  205. context.lineTo(x, highlight.scrollY + markLength);
  206. context.stroke();
  207. }
  208. context.strokeStyle = lightGridColor;
  209. for (var x = gridSubStep; x < highlight.scrollX + width; x += gridSubStep) {
  210. if (!(x % gridStep))
  211. continue;
  212. context.beginPath();
  213. context.moveTo(x, highlight.scrollY);
  214. context.lineTo(x, highlight.scrollY + gridSubStep);
  215. context.stroke();
  216. }
  217. context.restore();
  218. }
  219. context.restore();
  220. }
  221. function quadToPath(quad)
  222. {
  223. context.beginPath();
  224. context.moveTo(quad[0].x, quad[0].y);
  225. context.lineTo(quad[1].x, quad[1].y);
  226. context.lineTo(quad[2].x, quad[2].y);
  227. context.lineTo(quad[3].x, quad[3].y);
  228. context.closePath();
  229. return context;
  230. }
  231. function drawOutlinedQuad(quad, fillColor, outlineColor)
  232. {
  233. context.save();
  234. context.lineWidth = 2;
  235. quadToPath(quad).clip();
  236. context.fillStyle = fillColor;
  237. context.fill();
  238. if (outlineColor) {
  239. context.strokeStyle = outlineColor;
  240. context.stroke();
  241. }
  242. context.restore();
  243. }
  244. function drawOutlinedQuadWithClip(quad, clipQuad, fillColor)
  245. {
  246. var canvas = document.getElementById("canvas");
  247. context.fillStyle = fillColor;
  248. context.save();
  249. context.lineWidth = 0;
  250. quadToPath(quad).fill();
  251. context.globalCompositeOperation = "destination-out";
  252. context.fillStyle = "red";
  253. quadToPath(clipQuad).fill();
  254. context.restore();
  255. }
  256. function quadEquals(quad1, quad2)
  257. {
  258. return quad1[0].x === quad2[0].x && quad1[0].y === quad2[0].y &&
  259. quad1[1].x === quad2[1].x && quad1[1].y === quad2[1].y &&
  260. quad1[2].x === quad2[2].x && quad1[2].y === quad2[2].y &&
  261. quad1[3].x === quad2[3].x && quad1[3].y === quad2[3].y;
  262. }
  263. function drawGutter()
  264. {
  265. var frameWidth = frameViewFullSize.width;
  266. var frameHeight = frameViewFullSize.height;
  267. if (!frameWidth || document.body.offsetWidth <= frameWidth)
  268. rightGutter.style.removeProperty("display");
  269. else {
  270. rightGutter.style.display = "block";
  271. rightGutter.style.left = frameWidth + "px";
  272. }
  273. if (!frameHeight || document.body.offsetHeight <= frameHeight)
  274. bottomGutter.style.removeProperty("display");
  275. else {
  276. bottomGutter.style.display = "block";
  277. bottomGutter.style.top = frameHeight + "px";
  278. }
  279. }
  280. function reset(resetData)
  281. {
  282. var deviceScaleFactor = resetData.deviceScaleFactor;
  283. var viewportSize = resetData.viewportSize;
  284. window.frameViewFullSize = resetData.frameViewFullSize;
  285. window.canvas = document.getElementById("canvas");
  286. window.context = canvas.getContext("2d");
  287. window.rightGutter = document.getElementById("right-gutter");
  288. window.bottomGutter = document.getElementById("bottom-gutter");
  289. canvas.width = deviceScaleFactor * viewportSize.width;
  290. canvas.height = deviceScaleFactor * viewportSize.height;
  291. canvas.style.width = viewportSize.width + "px";
  292. canvas.style.height = viewportSize.height + "px";
  293. context.scale(deviceScaleFactor, deviceScaleFactor);
  294. document.getElementById("paused-in-debugger").style.visibility = "hidden";
  295. document.getElementById("element-title").style.visibility = "hidden";
  296. document.body.classList.remove("dimmed");
  297. }
  298. function _drawElementTitle(highlight)
  299. {
  300. var elementInfo = highlight.elementInfo;
  301. if (!highlight.elementInfo)
  302. return;
  303. document.getElementById("tag-name").textContent = elementInfo.tagName;
  304. document.getElementById("node-id").textContent = elementInfo.idValue ? "#" + elementInfo.idValue : "";
  305. var className = elementInfo.className;
  306. if (className && className.length > 50)
  307. className = className.substring(0, 50) + "\u2026";
  308. document.getElementById("class-name").textContent = className || "";
  309. document.getElementById("node-width").textContent = elementInfo.nodeWidth;
  310. document.getElementById("node-height").textContent = elementInfo.nodeHeight;
  311. var elementTitle = document.getElementById("element-title");
  312. var marginQuad = highlight.quads[0];
  313. var titleWidth = elementTitle.offsetWidth + 6;
  314. var titleHeight = elementTitle.offsetHeight + 4;
  315. var anchorTop = marginQuad[0].y;
  316. var anchorBottom = marginQuad[3].y
  317. const arrowHeight = 7;
  318. var renderArrowUp = false;
  319. var renderArrowDown = false;
  320. var boxX = Math.max(2, marginQuad[0].x);
  321. if (boxX + titleWidth > canvas.width)
  322. boxX = canvas.width - titleWidth - 2;
  323. var boxY;
  324. if (anchorTop > canvas.height) {
  325. boxY = canvas.height - titleHeight - arrowHeight;
  326. renderArrowDown = true;
  327. } else if (anchorBottom < 0) {
  328. boxY = arrowHeight;
  329. renderArrowUp = true;
  330. } else if (anchorBottom + titleHeight + arrowHeight < canvas.height) {
  331. boxY = anchorBottom + arrowHeight - 4;
  332. renderArrowUp = true;
  333. } else if (anchorTop - titleHeight - arrowHeight > 0) {
  334. boxY = anchorTop - titleHeight - arrowHeight + 3;
  335. renderArrowDown = true;
  336. } else
  337. boxY = arrowHeight;
  338. context.save();
  339. context.translate(0.5, 0.5);
  340. context.beginPath();
  341. context.moveTo(boxX, boxY);
  342. if (renderArrowUp) {
  343. context.lineTo(boxX + 2 * arrowHeight, boxY);
  344. context.lineTo(boxX + 3 * arrowHeight, boxY - arrowHeight);
  345. context.lineTo(boxX + 4 * arrowHeight, boxY);
  346. }
  347. context.lineTo(boxX + titleWidth, boxY);
  348. context.lineTo(boxX + titleWidth, boxY + titleHeight);
  349. if (renderArrowDown) {
  350. context.lineTo(boxX + 4 * arrowHeight, boxY + titleHeight);
  351. context.lineTo(boxX + 3 * arrowHeight, boxY + titleHeight + arrowHeight);
  352. context.lineTo(boxX + 2 * arrowHeight, boxY + titleHeight);
  353. }
  354. context.lineTo(boxX, boxY + titleHeight);
  355. context.closePath();
  356. context.fillStyle = "rgb(255, 255, 194)";
  357. context.fill();
  358. context.strokeStyle = "rgb(128, 128, 128)";
  359. context.stroke();
  360. context.restore();
  361. elementTitle.style.visibility = "visible";
  362. elementTitle.style.top = (boxY + 3) + "px";
  363. elementTitle.style.left = (boxX + 3) + "px";
  364. }
  365. function _drawRulers(highlight, rulerAtRight, rulerAtBottom)
  366. {
  367. if (!highlight.showRulers)
  368. return;
  369. context.save();
  370. var width = canvas.width;
  371. var height = canvas.height;
  372. context.strokeStyle = "rgba(128, 128, 128, 0.3)";
  373. context.lineWidth = 1;
  374. context.translate(0.5, 0.5);
  375. var leftmostXForY = {};
  376. var rightmostXForY = {};
  377. var topmostYForX = {};
  378. var bottommostYForX = {};
  379. for (var i = 0; i < highlight.quads.length; ++i) {
  380. var quad = highlight.quads[i];
  381. for (var j = 0; j < quad.length; ++j) {
  382. var x = quad[j].x;
  383. var y = quad[j].y;
  384. leftmostXForY[Math.round(y)] = Math.min(leftmostXForY[y] || Number.MAX_VALUE, Math.round(quad[j].x));
  385. rightmostXForY[Math.round(y)] = Math.max(rightmostXForY[y] || Number.MIN_VALUE, Math.round(quad[j].x));
  386. topmostYForX[Math.round(x)] = Math.min(topmostYForX[x] || Number.MAX_VALUE, Math.round(quad[j].y));
  387. bottommostYForX[Math.round(x)] = Math.max(bottommostYForX[x] || Number.MIN_VALUE, Math.round(quad[j].y));
  388. }
  389. }
  390. if (rulerAtRight) {
  391. for (var y in rightmostXForY) {
  392. context.beginPath();
  393. context.moveTo(width, y);
  394. context.lineTo(rightmostXForY[y], y);
  395. context.stroke();
  396. }
  397. } else {
  398. for (var y in leftmostXForY) {
  399. context.beginPath();
  400. context.moveTo(0, y);
  401. context.lineTo(leftmostXForY[y], y);
  402. context.stroke();
  403. }
  404. }
  405. if (rulerAtBottom) {
  406. for (var x in bottommostYForX) {
  407. context.beginPath();
  408. context.moveTo(x, height);
  409. context.lineTo(x, topmostYForX[x]);
  410. context.stroke();
  411. }
  412. } else {
  413. for (var x in topmostYForX) {
  414. context.beginPath();
  415. context.moveTo(x, 0);
  416. context.lineTo(x, topmostYForX[x]);
  417. context.stroke();
  418. }
  419. }
  420. context.restore();
  421. }
  422. function drawNodeHighlight(highlight)
  423. {
  424. if (!highlight.quads.length) {
  425. _drawGrid(highlight, false, false);
  426. return;
  427. }
  428. context.save();
  429. for (var i = 0; i < highlight.quads.length; ++i) {
  430. var quad = highlight.quads[i];
  431. for (var j = 0; j < quad.length; ++j) {
  432. quad[j].x -= highlight.scrollX;
  433. quad[j].y -= highlight.scrollY;
  434. }
  435. }
  436. var quads = highlight.quads.slice();
  437. var contentQuad = quads.pop();
  438. var paddingQuad = quads.pop();
  439. var borderQuad = quads.pop();
  440. var marginQuad = quads.pop();
  441. var hasContent = contentQuad && highlight.contentColor !== transparentColor || highlight.contentOutlineColor !== transparentColor;
  442. var hasPadding = paddingQuad && highlight.paddingColor !== transparentColor;
  443. var hasBorder = borderQuad && highlight.borderColor !== transparentColor;
  444. var hasMargin = marginQuad && highlight.marginColor !== transparentColor;
  445. var clipQuad;
  446. if (hasMargin && (!hasBorder || !quadEquals(marginQuad, borderQuad))) {
  447. drawOutlinedQuadWithClip(marginQuad, borderQuad, highlight.marginColor);
  448. clipQuad = borderQuad;
  449. }
  450. if (hasBorder && (!hasPadding || !quadEquals(borderQuad, paddingQuad))) {
  451. drawOutlinedQuadWithClip(borderQuad, paddingQuad, highlight.borderColor);
  452. clipQuad = paddingQuad;
  453. }
  454. if (hasPadding && (!hasContent || !quadEquals(paddingQuad, contentQuad))) {
  455. drawOutlinedQuadWithClip(paddingQuad, contentQuad, highlight.paddingColor);
  456. clipQuad = contentQuad;
  457. }
  458. if (hasContent)
  459. drawOutlinedQuad(contentQuad, highlight.contentColor, highlight.contentOutlineColor);
  460. var width = canvas.width;
  461. var height = canvas.height;
  462. var minX = Number.MAX_VALUE, minY = Number.MAX_VALUE, maxX = Number.MIN_VALUE; maxY = Number.MIN_VALUE;
  463. for (var i = 0; i < highlight.quads.length; ++i) {
  464. var quad = highlight.quads[i];
  465. for (var j = 0; j < quad.length; ++j) {
  466. minX = Math.min(minX, quad[j].x);
  467. maxX = Math.max(maxX, quad[j].x);
  468. minY = Math.min(minY, quad[j].y);
  469. maxY = Math.max(maxY, quad[j].y);
  470. }
  471. }
  472. var rulerAtRight = minX < 20 && maxX + 20 < width;
  473. var rulerAtBottom = minY < 20 && maxY + 20 < height;
  474. _drawGrid(highlight, rulerAtRight, rulerAtBottom);
  475. _drawRulers(highlight, rulerAtRight, rulerAtBottom);
  476. _drawElementTitle(highlight);
  477. context.restore();
  478. }
  479. function drawQuadHighlight(highlight)
  480. {
  481. context.save();
  482. drawOutlinedQuad(highlight.quads[0], highlight.contentColor, highlight.contentOutlineColor);
  483. context.restore();
  484. }
  485. function setPlatform(platform)
  486. {
  487. document.body.classList.add("platform-" + platform);
  488. }
  489. function dispatch(message)
  490. {
  491. var functionName = message.shift();
  492. window[functionName].apply(null, message);
  493. }
  494. function log(text)
  495. {
  496. var logEntry = document.createElement("div");
  497. logEntry.textContent = text;
  498. document.getElementById("log").appendChild(logEntry);
  499. }
  500. </script>
  501. </head>
  502. <body class="fill">
  503. <div class="message-line"><span class="message-box" id="paused-in-debugger"></span></div>
  504. </body>
  505. <canvas id="canvas" class="fill"></canvas>
  506. <div id="element-title">
  507. <span id="tag-name"></span><span id="node-id"></span><span id="class-name"></span>
  508. <span id="node-width"></span><span class="px">px</span><span class="px"> &#xD7; </span><span id="node-height"></span><span class="px">px</span>
  509. </div>
  510. <div id="right-gutter"></div>
  511. <div id="bottom-gutter"></div>
  512. <div id="log"></div>
  513. </html>