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 |