16f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.comvar MAX_SWAP_IMG_SIZE = 400;
2513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.comvar MAGNIFIER_WIDTH = 200;
3513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.comvar MAGNIFIER_HEIGHT = 200;
4513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.comvar MAGNIFIER_HALF_WIDTH = MAGNIFIER_WIDTH * 0.5;
5513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.comvar MAGNIFIER_HALF_HEIGHT = MAGNIFIER_HEIGHT * 0.5;
6513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com// TODO add support for a magnified scale factor
7513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.comvar MAGNIFIER_SCALE_FACTOR = 2.0;
86f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com
91bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.comangular.module('diff_viewer', []).
10513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.comdirective('imgCompare', function() {
11513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com  // Custom directive for comparing (3-way) images
12513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com  return {
13513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com      restrict: 'E', // The directive can be used as an element name
14513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com      replace: true, // The directive replaces itself with the template
15513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com      template: '<canvas/>',
16513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com      scope: true,
17513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com      link: function(scope, elm, attrs, ctrl) {
18513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          var image = new Image();
19513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          var canvas = elm[0];
20513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          var ctx = canvas.getContext('2d');
21513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
22513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          var magnifyContent = false;
232cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org          var maskCanvas = false;
24513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
25513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          // When the type attribute changes, load the image and then render
26513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          attrs.$observe('type', function(value) {
27513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              switch(value) {
28513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                case "alphaMask":
29513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                    image.src = scope.record.differencePath;
302cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org                    maskCanvas = true;
31513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                    break;
32513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                case "baseline":
33513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                    image.src = scope.record.baselinePath;
34513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                    magnifyContent = true;
35513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                    break;
36513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                case "test":
37513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                    image.src = scope.record.testPath;
38513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                    magnifyContent = true;
39513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                    break;
40513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                default:
41513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                    console.log("Unknown type attribute on <img-compare>: " + value);
42513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                    return;
43513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              }
44513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
45513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              image.onload = function() {
46513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                  // compute the scaled image width/height for image and canvas
47513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                  var divisor = 1;
48513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                  // Make it so the maximum size of an image is MAX_SWAP_IMG_SIZE,
49513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                  // and the images are scaled down in halves.
50513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                  while ((image.width / divisor) > MAX_SWAP_IMG_SIZE) {
51513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                      divisor *= 2;
52513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                  }
53513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
54513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                  scope.setImgScaleFactor(1 / divisor);
55513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
56513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                  // Set canvas to correct size
57513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                  canvas.width = image.width * scope.imgScaleFactor;
58513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                  canvas.height = image.height * scope.imgScaleFactor;
59513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
602cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org                  // update the size for non-alphaMask canvas when loading baseline image
612cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org                  if (!scope.maskSizeUpdated) {
622cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org                      if (!maskCanvas) {
632cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org                          scope.updateMaskCanvasSize({width: canvas.width, height: canvas.height});
642cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org                      }
652cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org                      scope.maskCanvasSizeUpdated(true);
662cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org                  }
672cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org
68513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                  // render the image onto the canvas
69513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                  scope.renderImage();
70513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              }
71513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          });
72513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
732cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org          // when updatedMaskSize changes, update mask canvas size.
742cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org          scope.$watch('updatedMaskSize', function(updatedSize) {
752cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org              if (!maskCanvas) {
762cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org                  return;
772cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org              }
782cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org
792cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org              canvas.width = updatedSize.width;
802cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org              canvas.height = updatedSize.height;
812cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org          });
822cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org
83513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          // When the magnify attribute changes, render the magnified rect at
84513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          // the default zoom level.
85513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          scope.$watch('magnifyCenter', function(magCenter) {
86513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              if (!magnifyContent) {
87513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                  return;
88513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              }
89513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
90513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              scope.renderImage();
91513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
92513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              if (!magCenter) {
93513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                  return;
94513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              }
95513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
96513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              var magX = magCenter.x - MAGNIFIER_HALF_WIDTH;
97513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              var magY = magCenter.y - MAGNIFIER_HALF_HEIGHT;
98513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
99513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              var magMaxX = canvas.width - MAGNIFIER_WIDTH;
100513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              var magMaxY = canvas.height - MAGNIFIER_HEIGHT;
101513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
102513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              var magRect = { x: Math.max(0, Math.min(magX, magMaxX)),
103513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                              y: Math.max(0, Math.min(magY, magMaxY)),
104513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                              width: MAGNIFIER_WIDTH,
105513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                              height: MAGNIFIER_HEIGHT
106513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                            };
107513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
108513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              var imgRect = { x: (magCenter.x / scope.imgScaleFactor) - MAGNIFIER_HALF_WIDTH,
109513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                              y: (magCenter.y  / scope.imgScaleFactor) - MAGNIFIER_HALF_HEIGHT,
110513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                              width: MAGNIFIER_WIDTH,
111513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                              height: MAGNIFIER_HEIGHT
112513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                            };
1131bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com
114513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              // draw the magnified image
115513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              ctx.clearRect(magRect.x, magRect.y, magRect.width, magRect.height);
116513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              ctx.drawImage(image, imgRect.x, imgRect.y, imgRect.width, imgRect.height,
117513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                            magRect.x, magRect.y, magRect.width, magRect.height);
118513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
119513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              // draw the outline rect
120513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              ctx.beginPath();
121513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              ctx.rect(magRect.x, magRect.y, magRect.width, magRect.height);
122513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              ctx.lineWidth = 2;
123513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              ctx.strokeStyle = 'red';
124513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              ctx.stroke();
125513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
126513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          });
127513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
128513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          // render the image to the canvas. This is often done every frame prior
129513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          // to any special effects (i.e. magnification).
130513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          scope.renderImage = function() {
131513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com            ctx.clearRect(0, 0, canvas.width, canvas.height);
132513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com            ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
133513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          };
134513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
135513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          // compute a rect (x,y,width,height) that represents the bounding box for
136513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          // the magnification effect
137513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          scope.computeMagnifierOutline = function(event) {
138513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com            var scaledWidth = MAGNIFIER_WIDTH * scope.imgScaleFactor;
139513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com            var scaledHeight = MAGNIFIER_HEIGHT * scope.imgScaleFactor;
140513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com            return {
141513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              x: event.offsetX - (scaledWidth * 0.5),
142513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              y: event.offsetY  - (scaledHeight * 0.5),
143513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              width: scaledWidth,
144513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              height: scaledHeight
1451bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com            };
146513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          };
147513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
148513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          // event handler for mouse events that triggers the magnification
149513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          // effect across the 3 images being compared.
150513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          scope.MagnifyDraw = function(event, startMagnify) {
151513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              if (startMagnify) {
152513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                  scope.setMagnifierState(true);
153513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              }  else if (!scope.magnifierOn) {
154513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com                  return;
155513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              }
156513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
157513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              scope.renderImage();
158513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
159513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              // render the magnifier outline rect
160513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              var rect = scope.computeMagnifierOutline(event);
161513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              ctx.save();
162513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              ctx.beginPath();
163513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              ctx.rect(rect.x, rect.y, rect.width, rect.height);
164513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              ctx.lineWidth = 2;
165513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              ctx.strokeStyle = 'red';
166513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              ctx.stroke();
167513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              ctx.restore();
168513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
169513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              // update scope on baseline / test that will cause them to render
170513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              scope.setMagnifyCenter({x: event.offsetX, y: event.offsetY});
171513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          };
172513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
173513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          // event handler that triggers the end of the magnification effect and
174513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          // resets all the canvases to their original state.
175513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com          scope.MagnifyEnd = function(event) {
176513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              scope.renderImage();
177513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              // update scope on baseline / test that will cause them to render
178513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              scope.setMagnifierState(false);
179513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com              scope.setMagnifyCenter(undefined);
180513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com        };
181513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com      }
182513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com  };
1831bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com});
1841bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com
185513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.comfunction ImageController($scope, $http, $location, $timeout, $parse) {
186513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com  $scope.imgScaleFactor = 1.0;
187513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com  $scope.magnifierOn = false;
188513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com  $scope.magnifyCenter = undefined;
1892cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org  $scope.updatedMaskSize = undefined;
1902cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org  $scope.maskSizeUpdated = false;
191513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
192513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com  $scope.setImgScaleFactor = function(scaleFactor) {
193513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com    $scope.imgScaleFactor = scaleFactor;
194513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com  }
195513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
196513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com  $scope.setMagnifierState = function(magnifierOn) {
197513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com    $scope.magnifierOn = magnifierOn;
198513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com  }
199513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
200513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com  $scope.setMagnifyCenter = function(magnifyCenter) {
201513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com      $scope.magnifyCenter = magnifyCenter;
202513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com  }
2032cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org
2042cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org  $scope.updateMaskCanvasSize = function(updatedSize) {
2052cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org      $scope.updatedMaskSize = updatedSize;
2062cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org  }
2072cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org
2082cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org  $scope.maskCanvasSizeUpdated = function(flag) {
2092cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org      $scope.maskSizeUpdated = flag;
2102cce3df19adc4bbda837d30f7f533938f579b478commit-bot@chromium.org  }
211513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com}
212513a7bffd344a2bba6e014ec08838ea0bbb8aa68djsollen@google.com
21374c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.comfunction DiffListController($scope, $http, $location, $timeout, $parse) {
21474c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com    // Detect if we are running the web server version of the viewer. If so, we set a flag and
21574c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com    // enable some extra functionality of the website for rebaselining.
21674c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com    $scope.isDynamic = ($location.protocol() == "http" || $location.protocol() == "https");
21774c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com
2181bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com    // Label each kind of differ for the sort buttons.
2199432c0c2843112c293be2630421ddc52cbf62583zachr@google.com    $scope.differs = [
2209432c0c2843112c293be2630421ddc52cbf62583zachr@google.com        {
2219432c0c2843112c293be2630421ddc52cbf62583zachr@google.com            "title": "Different Pixels"
2229432c0c2843112c293be2630421ddc52cbf62583zachr@google.com        },
2239432c0c2843112c293be2630421ddc52cbf62583zachr@google.com        {
2249432c0c2843112c293be2630421ddc52cbf62583zachr@google.com            "title": "Perceptual Difference"
2259432c0c2843112c293be2630421ddc52cbf62583zachr@google.com        }
2269432c0c2843112c293be2630421ddc52cbf62583zachr@google.com    ];
2271bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com
2281bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com    // Puts the records within AngularJS scope
2299432c0c2843112c293be2630421ddc52cbf62583zachr@google.com    $scope.records = SkPDiffRecords.records;
2301bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com
23174c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com    // Keep track of the index of the last record to change so that shift clicking knows what range
23274c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com    // of records to apply the action to.
23374c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com    $scope.lastSelectedIndex = undefined;
23474c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com
2351bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com    // Indicates which diff metric is used for sorting
2361bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com    $scope.sortIndex = 1;
2371bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com
2381bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com    // Called by the sort buttons to adjust the metric used for sorting
2391bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com    $scope.setSortIndex = function(idx) {
2401bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com        $scope.sortIndex = idx;
24174c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com
24274c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        // Because the index of things has most likely changed, the ranges of shift clicking no
24374c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        // longer make sense from the user's point of view. We reset it to avoid confusion.
24474c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        $scope.lastSelectedIndex = undefined;
2451bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com    };
2461bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com
2471bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com    // A predicate for pulling out the number used for sorting
2481bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com    $scope.sortingDiffer = function(record) {
2491bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com        return record.diffs[$scope.sortIndex].result;
2501bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com    };
2516f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com
25274c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com    // Flash status indicator on the page, and then remove it so the style can potentially be
2536f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com    // reapplied later.
25474c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com    $scope.flashStatus = function(success) {
2556f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com        var flashStyle = success ? "success-flash" : "failure-flash";
2566f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com        var flashDurationMillis = success ? 500 : 800;
2576f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com
2586f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com        // Store the style in the record. The row will pick up the style this way instead of through
2596f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com        // index because index can change with sort order.
26074c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        $scope.statusClass = flashStyle;
2616f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com
2626f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com        // The animation cannot be repeated unless the class is removed the element.
2636f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com        $timeout(function() {
26474c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com            $scope.statusClass = "";
2656f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com        }, flashDurationMillis);
26674c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com    };
26774c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com
26874c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com    $scope.selectedRebaseline = function(index, event) {
26974c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        // Retrieve the records in the same order they are displayed.
27074c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        var recordsInOrder = $parse("records | orderBy:sortingDiffer")($scope);
27174c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com
27274c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        // If the user is shift clicking, apply the last tick/untick to all elements in between this
27374c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        // record, and the last one they ticked/unticked.
27474c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        if (event.shiftKey && $scope.lastSelectedIndex !== undefined) {
27574c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com            var currentAction = recordsInOrder[index].isRebaselined;
27674c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com            var smallerIndex = Math.min($scope.lastSelectedIndex, index);
27774c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com            var largerIndex = Math.max($scope.lastSelectedIndex, index);
27874c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com            for (var recordIndex = smallerIndex; recordIndex <= largerIndex; recordIndex++) {
27974c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com                recordsInOrder[recordIndex].isRebaselined = currentAction;
28074c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com            }
28174c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com            $scope.lastSelectedIndex = index;
28274c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        }
28374c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        else
28474c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        {
28574c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com            $scope.lastSelectedIndex = index;
28674c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        }
28774c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com
28874c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com    };
2896f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com
29074c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com    $scope.commitRebaselines = function() {
29174c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        // Gather up all records that have the rebaseline set.
29274c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        var rebaselines = [];
29374c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        for (var recordIndex = 0; recordIndex < $scope.records.length; recordIndex++) {
29474c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com            if ($scope.records[recordIndex].isRebaselined) {
29574c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com                rebaselines.push($scope.records[recordIndex].testPath);
29674c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com            }
29774c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        }
29874c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com        $http.post("/commit_rebaselines", {
29974c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com            "rebaselines": rebaselines
3006f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com        }).success(function(data) {
30174c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com            $scope.flashStatus(data.success);
3026f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com        }).error(function() {
30374c5ab19fd69d3c030f53e5b64493d548b74f916zachr@google.com            $scope.flashStatus(false);
3046f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com        });
3056f8e2c5e87bd6620ff5290a9a8b6d5b570366336zachr@google.com    };
3061bc995e68cac8621a7efce3c2ccac88da1b8d3c2zachr@google.com}
307