OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 | 5 |
6 // Namespace object for the utilities. | 6 // Namespace object for the utilities. |
7 function ImageUtil() {} | 7 function ImageUtil() {} |
8 | 8 |
9 // Performance trace. | 9 // Performance trace. |
10 ImageUtil.trace = (function() { | 10 ImageUtil.trace = (function() { |
(...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
323 /* | 323 /* |
324 * ImageLoader loads an image from a given URL into a canvas in two steps: | 324 * ImageLoader loads an image from a given URL into a canvas in two steps: |
325 * 1. Loads the image into an HTMLImageElement. | 325 * 1. Loads the image into an HTMLImageElement. |
326 * 2. Copies pixels from HTMLImageElement to HTMLCanvasElement. This is done | 326 * 2. Copies pixels from HTMLImageElement to HTMLCanvasElement. This is done |
327 * stripe-by-stripe to avoid freezing up the UI. The transform is taken into | 327 * stripe-by-stripe to avoid freezing up the UI. The transform is taken into |
328 * account. | 328 * account. |
329 */ | 329 */ |
330 | 330 |
331 ImageUtil.ImageLoader = function(document) { | 331 ImageUtil.ImageLoader = function(document) { |
332 this.document_ = document; | 332 this.document_ = document; |
333 this.image_ = new Image(); | 333 this.image_ = null; |
334 }; | 334 }; |
335 | 335 |
336 /** | 336 /** |
337 * @param {string} url | 337 * @param {string} url |
338 * @param {{scaleX: number, scaleY: number, rotate90: number}} transform | 338 * @param {{scaleX: number, scaleY: number, rotate90: number}} transform |
339 * @param {function(HTMLCanvasElement} callback | 339 * @param {function(HTMLCanvasElement} callback |
340 * @param {number} opt_delay Load delay in milliseconds, useful to let the | 340 * @param {number} opt_delay Load delay in milliseconds, useful to let the |
341 * animations play out before the computation heavy image loading starts. | 341 * animations play out before the computation heavy image loading starts. |
342 */ | 342 */ |
343 ImageUtil.ImageLoader.prototype.load = function( | 343 ImageUtil.ImageLoader.prototype.load = function( |
344 url, transform, callback, opt_delay) { | 344 url, transform, callback, opt_delay) { |
345 this.cancel(); | 345 this.cancel(); |
346 | 346 |
347 this.url_ = url; | 347 this.url_ = url; |
348 this.transform_ = transform || { scaleX: 1, scaleY: 1, rotate90: 0}; | 348 this.transform_ = transform || { scaleX: 1, scaleY: 1, rotate90: 0}; |
349 this.callback_ = callback; | 349 this.callback_ = callback; |
350 | 350 |
351 var self = this; | 351 var self = this; |
352 function startLoad() { | 352 function startLoad() { |
353 self.timeout_ = null; | 353 self.timeout_ = null; |
354 self.image_.onload = self.convertImage_.bind(self); | 354 // The clients of this class sometimes request the same url repeatedly. |
355 // The onload fires only if the src is different from the previous value. | |
356 // To work around that we create a new Image every time. | |
357 self.image_ = new Image(); | |
358 self.image_.onload = function(e) { | |
359 self.image_ = null; | |
360 self.convertImage_(e.target); | |
361 }; | |
355 self.image_.src = url; | 362 self.image_.src = url; |
356 } | 363 } |
357 if (opt_delay) { | 364 if (opt_delay) { |
358 this.timeout_ = setTimeout(startLoad, opt_delay); | 365 this.timeout_ = setTimeout(startLoad, opt_delay); |
359 } else { | 366 } else { |
360 startLoad(); | 367 startLoad(); |
361 } | 368 } |
362 }; | 369 }; |
363 | 370 |
364 ImageUtil.ImageLoader.prototype.isBusy = function() { | 371 ImageUtil.ImageLoader.prototype.isBusy = function() { |
365 return !!this.callback_; | 372 return !!this.callback_; |
366 }; | 373 }; |
367 | 374 |
368 ImageUtil.ImageLoader.prototype.isLoading = function(url) { | 375 ImageUtil.ImageLoader.prototype.isLoading = function(url) { |
369 return this.isBusy() && (this.url_ == url); | 376 return this.isBusy() && (this.url_ == url); |
370 }; | 377 }; |
371 | 378 |
372 ImageUtil.ImageLoader.prototype.setCallback = function(callback) { | 379 ImageUtil.ImageLoader.prototype.setCallback = function(callback) { |
373 this.callback_ = callback; | 380 this.callback_ = callback; |
374 }; | 381 }; |
375 | 382 |
376 ImageUtil.ImageLoader.prototype.cancel = function() { | 383 ImageUtil.ImageLoader.prototype.cancel = function() { |
377 if (!this.callback_) return; | 384 if (!this.callback_) return; |
378 this.callback_ = null; | 385 this.callback_ = null; |
379 if (this.timeout_) { | 386 if (this.timeout_) { |
380 clearTimeout(this.timeout_); | 387 clearTimeout(this.timeout_); |
381 this.timeout_ = null; | 388 this.timeout_ = null; |
382 } | 389 } |
383 this.image_.onload = function(){}; | 390 if (this.image_) { |
391 this.image_.onload = function(){}; | |
392 this.image_ = null; | |
393 } | |
384 }; | 394 }; |
385 | 395 |
386 ImageUtil.ImageLoader.prototype.convertImage_ = function() { | 396 ImageUtil.ImageLoader.prototype.convertImage_ = function(image) { |
387 var canvas = this.document_.createElement('canvas'); | 397 var canvas = this.document_.createElement('canvas'); |
388 | 398 |
389 if (this.transform_.rotate90 & 1) { // Rotated +/-90deg, swap the dimensions. | 399 if (this.transform_.rotate90 & 1) { // Rotated +/-90deg, swap the dimensions. |
390 canvas.width = this.image_.height; | 400 canvas.width = image.height; |
391 canvas.height = this.image_.width; | 401 canvas.height = image.width; |
392 } else { | 402 } else { |
393 canvas.width = this.image_.width; | 403 canvas.width = image.width; |
394 canvas.height = this.image_.height; | 404 canvas.height = image.height; |
395 } | 405 } |
396 | 406 |
397 ImageUtil.trace.resetTimer('load-convert'); | 407 ImageUtil.trace.resetTimer('load-convert'); |
398 | 408 |
399 var context = canvas.getContext('2d'); | 409 var context = canvas.getContext('2d'); |
400 context.save(); | 410 context.save(); |
401 context.translate(canvas.width / 2, canvas.height / 2); | 411 context.translate(canvas.width / 2, canvas.height / 2); |
402 context.rotate(this.transform_.rotate90 * Math.PI/2); | 412 context.rotate(this.transform_.rotate90 * Math.PI/2); |
403 context.scale(this.transform_.scaleX, this.transform_.scaleY); | 413 context.scale(this.transform_.scaleX, this.transform_.scaleY); |
404 | 414 |
405 var stripCount = | 415 var stripCount = Math.ceil (image.width * image.height / ( 1 << 21)); |
dgozman
2011/12/02 09:36:42
remove space after Math.ceil
Vladislav Kaznacheev
2011/12/02 09:52:36
Done.
| |
406 Math.ceil (this.image_.width * this.image_.height / ( 1 << 21)); | 416 var step = Math.max(16, Math.ceil(image.height / stripCount)) & 0xFFFFF0; |
407 var step = | |
408 Math.max(16, Math.ceil(this.image_.height / stripCount)) & 0xFFFFF0; | |
409 | 417 |
410 this.copyStrip_(context, 0, step); | 418 this.copyStrip_(context, image, 0, step); |
411 }; | 419 }; |
412 | 420 |
413 ImageUtil.ImageLoader.prototype.copyStrip_ = function( | 421 ImageUtil.ImageLoader.prototype.copyStrip_ = function( |
414 context, firstRow, rowCount) { | 422 context, image, firstRow, rowCount) { |
415 var lastRow = Math.min (firstRow + rowCount, this.image_.height); | 423 var lastRow = Math.min (firstRow + rowCount, image.height); |
416 | 424 |
417 context.drawImage( | 425 context.drawImage( |
418 this.image_, 0, firstRow, this.image_.width, lastRow - firstRow, | 426 image, 0, firstRow, image.width, lastRow - firstRow, |
419 -this.image_.width / 2, firstRow - this.image_.height / 2, | 427 -image.width / 2, firstRow - image.height / 2, |
420 this.image_.width, lastRow - firstRow); | 428 image.width, lastRow - firstRow); |
421 | 429 |
422 if (lastRow == this.image_.height) { | 430 if (lastRow == image.height) { |
423 context.restore(); | 431 context.restore(); |
424 ImageUtil.trace.reportTimer('load-convert'); | 432 ImageUtil.trace.reportTimer('load-convert'); |
425 var callback = this.callback_; | 433 var callback = this.callback_; |
426 this.callback_ = null; | 434 this.callback_ = null; |
427 callback(context.canvas); | 435 callback(context.canvas); |
428 } else { | 436 } else { |
429 var self = this; | 437 var self = this; |
430 this.timeout_ = setTimeout( | 438 this.timeout_ = setTimeout( |
431 function() { | 439 function() { |
432 self.timeout_ = null; | 440 self.timeout_ = null; |
433 self.copyStrip_(context, lastRow, rowCount); | 441 self.copyStrip_(context, image, lastRow, rowCount); |
434 }, 0); | 442 }, 0); |
435 } | 443 } |
436 }; | 444 }; |
437 | 445 |
438 ImageUtil.removeChildren = function(element) { | 446 ImageUtil.removeChildren = function(element) { |
439 element.textContent = ''; | 447 element.textContent = ''; |
440 }; | 448 }; |
441 | 449 |
442 ImageUtil.getFullNameFromUrl = function(url) { | 450 ImageUtil.getFullNameFromUrl = function(url) { |
443 if (url.indexOf('/') != -1) | 451 if (url.indexOf('/') != -1) |
(...skipping 14 matching lines...) Expand all Loading... | |
458 return ImageUtil.getFileNameFromFullName(ImageUtil.getFullNameFromUrl(url)); | 466 return ImageUtil.getFileNameFromFullName(ImageUtil.getFullNameFromUrl(url)); |
459 }; | 467 }; |
460 | 468 |
461 ImageUtil.replaceFileNameInFullName = function(fullName, name) { | 469 ImageUtil.replaceFileNameInFullName = function(fullName, name) { |
462 var index = fullName.lastIndexOf('.'); | 470 var index = fullName.lastIndexOf('.'); |
463 if (index != -1) | 471 if (index != -1) |
464 return name + fullName.substr(index); | 472 return name + fullName.substr(index); |
465 else | 473 else |
466 return name; | 474 return name; |
467 }; | 475 }; |
OLD | NEW |