1 /* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 // pixelzoomer is shared with LayoutTests/fast/harness/results.html 27 // Unfortuantely, there's no good way to share code between these two uses. 28 29 var pixelzoomer = pixelzoomer || {}; 30 31 (function() { 32 33 var kZoomFactor = 6; 34 var kDelayTimeoutMS = 400; 35 36 var kResultWidth = 800; 37 var kResultHeight = 600; 38 39 var kZoomedResultWidth = kResultWidth * kZoomFactor; 40 var kZoomedResultHeight = kResultHeight * kZoomFactor; 41 42 function matchesSelector(node, selector) 43 { 44 if (node.webkitMatchesSelector) 45 return node.webkitMatchesSelector(selector); 46 47 if (node.mozMatchesSelector) 48 return node.mozMatchesSelector(selector); 49 } 50 51 function parentOfType(node, selector) 52 { 53 while (node = node.parentNode) { 54 if (matchesSelector(node, selector)) 55 return node; 56 } 57 return null; 58 } 59 60 function zoomImageContainer(url) 61 { 62 var container = document.createElement('div'); 63 container.className = 'zoom-image-container'; 64 65 var title = url.match(/\-([^\-]*)\.png/)[1]; 66 67 var label = document.createElement('div'); 68 label.className = 'label'; 69 label.appendChild(document.createTextNode(title)); 70 container.appendChild(label); 71 72 var imageContainer = document.createElement('div'); 73 imageContainer.className = 'scaled-image-container'; 74 75 var image = new Image(); 76 image.src = url; 77 image.style.display = 'none'; 78 79 var canvas = document.createElement('canvas'); 80 81 imageContainer.appendChild(image); 82 imageContainer.appendChild(canvas); 83 container.appendChild(imageContainer); 84 85 return container; 86 } 87 88 function createContainer(e) 89 { 90 var tbody = parentOfType(e.target, 'tbody'); 91 var row = tbody.querySelector('tr'); 92 var images = row.querySelectorAll('img[src$=".png"]'); 93 94 var container = document.createElement('div'); 95 container.className = 'pixel-zoom-container'; 96 97 for (var i = 0; i < images.length; i++) 98 container.appendChild(zoomImageContainer(images[i].src)); 99 100 document.body.appendChild(container); 101 drawAll(); 102 } 103 104 function draw(imageContainer) 105 { 106 var image = imageContainer.querySelector('img'); 107 var canvas = imageContainer.querySelector('canvas'); 108 109 if (!image.complete) { 110 image.onload = function() { 111 draw(imageContainer); 112 }; 113 return; 114 } 115 116 canvas.width = imageContainer.clientWidth; 117 canvas.height = imageContainer.clientHeight; 118 119 var ctx = canvas.getContext('2d'); 120 ctx.mozImageSmoothingEnabled = false; 121 ctx.imageSmoothingEnabled = false; 122 ctx.translate(imageContainer.clientWidth / 2, imageContainer.clientHeight / 2); 123 ctx.translate(-pixelzoomer._percentX * kZoomedResultWidth, -pixelzoomer._percentY * kZoomedResultHeight); 124 ctx.strokeRect(-1.5, -1.5, kZoomedResultWidth + 2, kZoomedResultHeight + 2); 125 ctx.scale(kZoomFactor, kZoomFactor); 126 ctx.drawImage(image, 0, 0); 127 } 128 129 function drawAll() 130 { 131 Array.prototype.forEach.call(document.querySelectorAll('.pixel-zoom-container .scaled-image-container'), draw); 132 } 133 134 function handleMouseOut(e) 135 { 136 if (e.relatedTarget && e.relatedTarget.tagName != 'IFRAME') 137 return; 138 139 // If e.relatedTarget is null, we've moused out of the document. 140 $('pixel-zoom-container').detach(); 141 } 142 143 function handleMouseMove(e) 144 { 145 if (pixelzoomer._mouseMoveTimeout) 146 clearTimeout(pixelzoomer._mouseMoveTimeout); 147 148 if (parentOfType(e.target, '.pixel-zoom-container')) 149 return; 150 151 var container = document.querySelector('.pixel-zoom-container'); 152 153 var resultContainer = (e.target.className == 'result-container') ? 154 e.target : parentOfType(e.target, '.result-container'); 155 if (!resultContainer || !resultContainer.querySelector('img')) { 156 $(container).detach(); 157 return; 158 } 159 160 var targetLocation = e.target.getBoundingClientRect(); 161 pixelzoomer._percentX = (e.clientX - targetLocation.left) / targetLocation.width; 162 pixelzoomer._percentY = (e.clientY - targetLocation.top) / targetLocation.height; 163 164 if (!container) { 165 if (pixelzoomer.showOnDelay) { 166 pixelzoomer._mouseMoveTimeout = setTimeout(function() { 167 createContainer(e); 168 }, kDelayTimeoutMS); 169 return; 170 } 171 172 createContainer(e); 173 return; 174 } 175 176 drawAll(); 177 } 178 179 pixelzoomer.showOnDelay = true; 180 181 pixelzoomer.installEventListeners = function() 182 { 183 document.addEventListener('mousemove', handleMouseMove, false); 184 document.addEventListener('mouseout', handleMouseOut, false); 185 }; 186 187 })(); 188