Chromium Code Reviews| 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 * Base class that Ribbon uses to display photos. | 6 * Base class that Ribbon uses to display photos. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 function RibbonClient() {} | 9 function RibbonClient() {} |
| 10 | 10 |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 218 function initRibbon() { | 218 function initRibbon() { |
| 219 self.ribbon_.load(urls, selectedIndex); | 219 self.ribbon_.load(urls, selectedIndex); |
| 220 // Flash the ribbon briefly to let the user know it is there. | 220 // Flash the ribbon briefly to let the user know it is there. |
| 221 self.cancelFading_(); | 221 self.cancelFading_(); |
| 222 self.initiateFading_(Gallery.FIRST_FADE_TIMEOUT); | 222 self.initiateFading_(Gallery.FIRST_FADE_TIMEOUT); |
| 223 } | 223 } |
| 224 | 224 |
| 225 var selectedURL = urls[selectedIndex]; | 225 var selectedURL = urls[selectedIndex]; |
| 226 // Initialize the ribbon only after the selected image is fully loaded. | 226 // Initialize the ribbon only after the selected image is fully loaded. |
| 227 this.metadataProvider_.fetch(selectedURL, function (metadata) { | 227 this.metadataProvider_.fetch(selectedURL, function (metadata) { |
| 228 // The first change is load, we should not count it. | 228 self.openImage(selectedIndex, selectedURL, metadata, 0, initRibbon); |
| 229 self.imageChanges_ = -1; | |
| 230 self.filenameEdit_.value = ImageUtil.getFileNameFromUrl(selectedURL); | |
| 231 self.editor_.openSession( | |
| 232 selectedIndex, selectedURL, metadata, 0, initRibbon); | |
| 233 }); | 229 }); |
| 234 }; | 230 }; |
| 235 | 231 |
| 236 Gallery.prototype.onImageContentChanged_ = function() { | 232 Gallery.prototype.onImageContentChanged_ = function() { |
| 237 this.imageChanges_++; | 233 this.imageChanges_++; |
| 238 if (this.imageChanges_ == 1) | 234 if (this.imageChanges_ == 1) { // First edit |
| 239 this.ribbon_.getSelectedItem().setCopyName(); | 235 this.ribbon_.getSelectedItem().setCopyName(); |
| 236 ImageUtil.metrics.recordUserAction(ImageUtil.getMetricName('Edit')); | |
| 237 } | |
| 240 this.updateFilename_(); | 238 this.updateFilename_(); |
| 241 }; | 239 }; |
| 242 | 240 |
| 243 Gallery.prototype.saveItem_ = function(item, callback, canvas, modified) { | 241 Gallery.prototype.saveItem_ = function(item, callback, canvas, modified) { |
| 244 if (modified) { | 242 if (modified) { |
| 245 item.save( | 243 item.save( |
| 246 this.parentDirEntry_, this.metadataProvider_, canvas, callback); | 244 this.parentDirEntry_, this.metadataProvider_, canvas, callback); |
| 247 } else { | 245 } else { |
| 248 if (callback) callback(); | 246 if (callback) callback(); |
| 249 } | 247 } |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 337 | 335 |
| 338 Gallery.prototype.onClose_ = function() { | 336 Gallery.prototype.onClose_ = function() { |
| 339 // TODO: handle write errors gracefully (suggest retry or saving elsewhere). | 337 // TODO: handle write errors gracefully (suggest retry or saving elsewhere). |
| 340 this.saveChanges_(this.closeCallback_); | 338 this.saveChanges_(this.closeCallback_); |
| 341 }; | 339 }; |
| 342 | 340 |
| 343 Gallery.prototype.prefetchImage = function(id, content, metadata) { | 341 Gallery.prototype.prefetchImage = function(id, content, metadata) { |
| 344 this.editor_.prefetchImage(id, content, metadata); | 342 this.editor_.prefetchImage(id, content, metadata); |
| 345 }; | 343 }; |
| 346 | 344 |
| 345 // Used for metrics reporting, keep in sync with the histogram description. | |
| 346 Gallery.FILE_TYPES = ['jpg', 'png', 'gif', 'bmp', 'webp']; | |
|
dgozman
2011/12/06 15:45:56
Move to ImageUtil near metric names?
Vladislav Kaznacheev
2011/12/06 16:07:44
Done.
| |
| 347 | |
| 347 Gallery.prototype.openImage = function(id, content, metadata, slide, callback) { | 348 Gallery.prototype.openImage = function(id, content, metadata, slide, callback) { |
| 348 // The first change is load, we should not count it. | 349 // The first change is load, we should not count it. |
| 349 this.imageChanges_ = -1; | 350 this.imageChanges_ = -1; |
| 350 this.updateFilename_(); | 351 |
| 351 this.editor_.openSession(id, content, metadata, slide, callback); | 352 var item = this.ribbon_.getSelectedItem(); |
| 353 if (item) { | |
| 354 this.updateFilename_(); | |
| 355 } else { | |
| 356 this.filenameEdit_.value = ImageUtil.getFileNameFromUrl(content); | |
| 357 } | |
| 358 | |
| 359 var self = this; | |
| 360 function loadDone() { | |
| 361 ImageUtil.metrics.recordUserAction(ImageUtil.getMetricName('View')); | |
| 362 | |
| 363 function toMillions(number) { return Math.round(number / (1000 * 1000)) } | |
| 364 | |
| 365 ImageUtil.metrics.recordSmallCount(ImageUtil.getMetricName('Size.MB'), | |
| 366 toMillions(metadata.fileSize)); | |
| 367 | |
| 368 var canvas = self.imageView_.getCanvas(); | |
| 369 ImageUtil.metrics.recordSmallCount(ImageUtil.getMetricName('Size.MPix'), | |
| 370 toMillions(canvas.width * canvas.height)); | |
| 371 | |
| 372 var url = item ? item.getUrl() : content; | |
| 373 var extIndex = url.lastIndexOf('.'); | |
| 374 var ext = extIndex < 0 ? '' : url.substr(extIndex + 1).toLowerCase(); | |
| 375 if (ext == 'jpeg') ext = 'jpg'; | |
| 376 ImageUtil.metrics.recordEnum( | |
| 377 ImageUtil.getMetricName('FileType'), ext, Gallery.FILE_TYPES); | |
| 378 | |
| 379 callback(arguments); | |
| 380 } | |
| 381 | |
| 382 this.editor_.openSession(id, content, metadata, slide, loadDone); | |
| 352 }; | 383 }; |
| 353 | 384 |
| 354 Gallery.prototype.closeImage = function(item) { | 385 Gallery.prototype.closeImage = function(item) { |
| 355 this.editor_.closeSession(this.saveItem_.bind(this, item, null)); | 386 this.editor_.closeSession(this.saveItem_.bind(this, item, null)); |
| 356 }; | 387 }; |
| 357 | 388 |
| 358 Gallery.prototype.isEditing_ = function() { | 389 Gallery.prototype.isEditing_ = function() { |
| 359 return this.container_.hasAttribute('editing'); | 390 return this.container_.hasAttribute('editing'); |
| 360 }; | 391 }; |
| 361 | 392 |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 585 | 616 |
| 586 var selectedItem = this.getSelectedItem(); | 617 var selectedItem = this.getSelectedItem(); |
| 587 selectedItem.select(true); | 618 selectedItem.select(true); |
| 588 this.redraw(); | 619 this.redraw(); |
| 589 | 620 |
| 590 var self = this; | 621 var self = this; |
| 591 selectedItem.fetchMetadata(this.metadataProvider_, function(metadata){ | 622 selectedItem.fetchMetadata(this.metadataProvider_, function(metadata){ |
| 592 if (!selectedItem.isSelected()) return; | 623 if (!selectedItem.isSelected()) return; |
| 593 self.client_.openImage( | 624 self.client_.openImage( |
| 594 selectedItem.getIndex(), selectedItem.getContent(), metadata, step, | 625 selectedItem.getIndex(), selectedItem.getContent(), metadata, step, |
| 595 function(loadedInstantly) { | 626 function(loadType) { |
| 596 if (!selectedItem.isSelected()) return; | 627 if (!selectedItem.isSelected()) return; |
| 597 if (Math.abs(step) != 1) return; | 628 if (Math.abs(step) != 1) return; |
| 598 if (loadedInstantly || (self.sequenceLength_ >= 3)) { | 629 if ((loadType == ImageView.LOAD_TYPE_CACHED_FULL) || |
| 630 (self.sequenceLength_ >= 3)) { | |
| 599 // We can always afford to prefetch if the previous load was | 631 // We can always afford to prefetch if the previous load was |
| 600 // instant. Even if it was not we should start prefetching | 632 // instant. Even if it was not we should start prefetching |
| 601 // if we have been going in the same direction for long enough. | 633 // if we have been going in the same direction for long enough. |
| 602 self.requestPrefetch(step); | 634 self.requestPrefetch(step); |
| 603 } | 635 } |
| 604 if (opt_callback) opt_callback(); | 636 if (opt_callback) opt_callback(); |
| 605 }); | 637 }); |
| 606 }); | 638 }); |
| 607 }; | 639 }; |
| 608 | 640 |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 791 if (this.canvas_) | 823 if (this.canvas_) |
| 792 return; // The image is being saved, the thumbnail is already up-to-date. | 824 return; // The image is being saved, the thumbnail is already up-to-date. |
| 793 | 825 |
| 794 var metadataEncoder = | 826 var metadataEncoder = |
| 795 ImageEncoder.encodeMetadata(this.getMetadata(), canvas, 1); | 827 ImageEncoder.encodeMetadata(this.getMetadata(), canvas, 1); |
| 796 this.setMetadata(metadataEncoder.getMetadata()); | 828 this.setMetadata(metadataEncoder.getMetadata()); |
| 797 }; | 829 }; |
| 798 | 830 |
| 799 Ribbon.Item.prototype.save = function( | 831 Ribbon.Item.prototype.save = function( |
| 800 dirEntry, metadataProvider, canvas, opt_callback) { | 832 dirEntry, metadataProvider, canvas, opt_callback) { |
| 833 | |
| 834 ImageUtil.metrics.startInterval(ImageUtil.getMetricName('SaveTime')); | |
|
dgozman
2011/12/06 15:45:56
Is it ok to not call recordInterval in the case of
Vladislav Kaznacheev
2011/12/06 16:07:44
Absolutely. The interval start time will stay in t
| |
| 835 | |
| 801 var metadataEncoder = | 836 var metadataEncoder = |
| 802 ImageEncoder.encodeMetadata(this.getMetadata(), canvas, 1); | 837 ImageEncoder.encodeMetadata(this.getMetadata(), canvas, 1); |
| 803 | 838 |
| 804 this.overrideContent(canvas, metadataEncoder.getMetadata()); | 839 this.overrideContent(canvas, metadataEncoder.getMetadata()); |
| 805 | 840 |
| 806 var self = this; | 841 var self = this; |
| 807 | 842 |
| 808 if (!dirEntry) { // Happens only in gallery_demo.js | 843 if (!dirEntry) { // Happens only in gallery_demo.js |
| 809 self.onSaveSuccess( | 844 self.onSaveSuccess( |
| 810 window.webkitURL.createObjectURL( | 845 window.webkitURL.createObjectURL( |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 917 Ribbon.Item.prototype.getContent = function () { | 952 Ribbon.Item.prototype.getContent = function () { |
| 918 return this.canvas_ || this.url_; | 953 return this.canvas_ || this.url_; |
| 919 }; | 954 }; |
| 920 | 955 |
| 921 Ribbon.Item.prototype.getMetadata = function () { | 956 Ribbon.Item.prototype.getMetadata = function () { |
| 922 return this.metadata_; | 957 return this.metadata_; |
| 923 }; | 958 }; |
| 924 | 959 |
| 925 Ribbon.Item.prototype.fetchMetadata = function (metadataProvider, callback) { | 960 Ribbon.Item.prototype.fetchMetadata = function (metadataProvider, callback) { |
| 926 if (this.metadata_) { | 961 if (this.metadata_) { |
| 927 setTimeout(callback.bind(null, this.metadata_), 0); | 962 callback(this.metadata_); // Every millisecond counts, call directly |
| 928 } else { | 963 } else { |
| 929 metadataProvider.fetch(this.getUrl(), callback); | 964 metadataProvider.fetch(this.getUrl(), callback); |
| 930 } | 965 } |
| 931 }; | 966 }; |
| 932 | 967 |
| 933 Ribbon.Item.prototype.onSaveSuccess = function(url) { | 968 Ribbon.Item.prototype.onSaveSuccess = function(url) { |
| 934 this.url_ = url; | 969 this.url_ = url; |
| 935 delete this.backupMetadata_; | 970 delete this.backupMetadata_; |
| 936 delete this.canvas_; | 971 delete this.canvas_; |
| 972 ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('Save'), 1, 2); | |
| 973 ImageUtil.metrics.recordInterval(ImageUtil.getMetricName('SaveTime')); | |
| 937 }; | 974 }; |
| 938 | 975 |
| 939 Ribbon.Item.prototype.onSaveError = function(error) { | 976 Ribbon.Item.prototype.onSaveError = function(error) { |
| 940 // TODO(kaznacheev): notify the user that the file write failed and | 977 // TODO(kaznacheev): notify the user that the file write failed and |
| 941 // suggest ways to rescue the modified image (retry/save elsewhere). | 978 // suggest ways to rescue the modified image (retry/save elsewhere). |
| 942 // For now - just drop the modified content and revert the thumbnail. | 979 // For now - just drop the modified content and revert the thumbnail. |
| 943 this.setMetadata(this.backupMetadata_); | 980 this.setMetadata(this.backupMetadata_); |
| 944 delete this.backupMetadata_; | 981 delete this.backupMetadata_; |
| 945 delete this.canvas_; | 982 delete this.canvas_; |
| 983 ImageUtil.metrics.recordEnum(ImageUtil.getMetricName('Save'), 0, 2); | |
| 946 }; | 984 }; |
| 947 | 985 |
| 948 Ribbon.MAX_THUMBNAIL_PIXEL_COUNT = 1 << 21; // 2 MPix | 986 Ribbon.MAX_THUMBNAIL_PIXEL_COUNT = 1 << 21; // 2 MPix |
| 949 Ribbon.MAX_THUMBNAIL_FILE_SIZE = 1 << 20; // 1 Mb | 987 Ribbon.MAX_THUMBNAIL_FILE_SIZE = 1 << 20; // 1 Mb |
| 950 | 988 |
| 951 Ribbon.Item.canUseImageForThumbnail = function(metadata) { | 989 Ribbon.Item.canUseImageForThumbnail = function(metadata) { |
| 952 return (metadata.fileSize && | 990 return (metadata.fileSize && |
| 953 metadata.fileSize <= Ribbon.MAX_THUMBNAIL_FILE_SIZE) || | 991 metadata.fileSize <= Ribbon.MAX_THUMBNAIL_FILE_SIZE) || |
| 954 (metadata.width && metadata.height && | 992 (metadata.width && metadata.height && |
| 955 (metadata.width * metadata.height <= Ribbon.MAX_THUMBNAIL_PIXEL_COUNT)); | 993 (metadata.width * metadata.height <= Ribbon.MAX_THUMBNAIL_PIXEL_COUNT)); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1061 ShareMode.prototype.setUp = function() { | 1099 ShareMode.prototype.setUp = function() { |
| 1062 ImageEditor.Mode.prototype.setUp.apply(this, arguments); | 1100 ImageEditor.Mode.prototype.setUp.apply(this, arguments); |
| 1063 ImageUtil.setAttribute(this.menu_, 'hidden', false); | 1101 ImageUtil.setAttribute(this.menu_, 'hidden', false); |
| 1064 ImageUtil.setAttribute(this.button_, 'pressed', false); | 1102 ImageUtil.setAttribute(this.button_, 'pressed', false); |
| 1065 }; | 1103 }; |
| 1066 | 1104 |
| 1067 ShareMode.prototype.cleanUpUI = function() { | 1105 ShareMode.prototype.cleanUpUI = function() { |
| 1068 ImageEditor.Mode.prototype.cleanUpUI.apply(this, arguments); | 1106 ImageEditor.Mode.prototype.cleanUpUI.apply(this, arguments); |
| 1069 ImageUtil.setAttribute(this.menu_, 'hidden', true); | 1107 ImageUtil.setAttribute(this.menu_, 'hidden', true); |
| 1070 }; | 1108 }; |
| OLD | NEW |