blob: 37b3f654ac4c5e06d1b25f65f0f875f568250cd6 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview
* 'cr-picture-pane' is a Polymer element used to show either a profile
* picture or a camera image preview.
*/
Polymer({
is: 'cr-picture-pane',
behaviors: [CrPngBehavior],
properties: {
/** Whether the camera is present / available */
cameraPresent: Boolean,
/** Image source to show when imageType != CAMERA. */
imageSrc: {
type: String,
observer: 'imageSrcChanged_',
},
/** Image URL to use when imageType != CAMERA. */
imageUrl: {
type: String,
value: '',
},
/**
* The type of image to display in the preview.
* @type {CrPicture.SelectionTypes}
*/
imageType: {
type: String,
value: CrPicture.SelectionTypes.NONE,
},
/** Strings provided by host */
discardImageLabel: String,
previewAltText: String,
takePhotoLabel: String,
captureVideoLabel: String,
switchModeToCameraLabel: String,
switchModeToVideoLabel: String,
/** Whether camera video mode is enabled */
cameraVideoModeEnabled: Boolean,
/** Whether the camera should be shown and active (started). */
cameraActive_: {
type: Boolean,
computed: 'getCameraActive_(cameraPresent, imageType)',
observer: 'cameraActiveChanged_',
},
},
/**
* Tells the camera to take a photo; the camera will fire a 'photo-taken'
* event when the photo is completed.
*/
takePhoto: function() {
const camera = /** @type {?CrCameraElement} */ (this.$$('#camera'));
if (camera)
camera.takePhoto();
},
/** Tells the pane to focus the main action button. */
focusActionButton: function() {
if (this.showDiscard_())
this.$.discardImage.focus();
else if (this.cameraActive_)
this.$$('#camera').focusTakePhotoButton();
},
/**
* @return {boolean}
* @private
*/
getCameraActive_: function() {
return this.cameraPresent &&
this.imageType == CrPicture.SelectionTypes.CAMERA;
},
/** @private */
cameraActiveChanged_: function() {
const camera = /** @type {?CrCameraElement} */ (this.$$('#camera'));
if (!camera)
return; // Camera will be started when attached.
if (this.cameraActive_)
camera.startCamera();
else
camera.stopCamera();
},
/** @private */
imageSrcChanged_: function() {
/**
* If current image URL is an object URL created below then revoke it to
* prevent this code from using more than one object URL per document.
*/
if (this.imageUrl.startsWith('blob:'))
URL.revokeObjectURL(this.imageUrl);
/**
* Data URLs for PNG images can be large. Create an object URL to avoid
* URL length limits.
*/
const image = /** @type {!HTMLImageElement} */ (this.$$('#image'));
if (this.imageSrc.startsWith('data:image/png')) {
const byteString = atob(this.imageSrc.split(',')[1]);
const bytes = new Uint8Array(byteString.length);
for (let i = 0; i < byteString.length; i++)
bytes[i] = byteString.charCodeAt(i);
const blob = new Blob([bytes], {'type': 'image/png'});
// Use first frame as placeholder while rest of image loads.
image.style.backgroundImage = 'url(' +
CrPngBehavior.convertImageSequenceToPng([this.imageSrc]) + ')';
this.imageUrl = URL.createObjectURL(blob);
} else {
image.style.backgroundImage = 'none';
this.imageUrl = this.imageSrc;
}
},
/**
* @return {boolean}
* @private
*/
showImagePreview_: function() {
return !this.cameraActive_ && !!this.imageSrc;
},
/**
* @return {boolean}
* @private
*/
showDiscard_: function() {
return this.imageType == CrPicture.SelectionTypes.OLD;
},
/** @private */
onTapDiscardImage_: function() {
this.fire('discard-image');
},
/**
* Returns the image to use for 'src'.
* @param {string} url
* @return {string}
* @private
*/
getImgSrc_: function(url) {
// Always use 2x user image for preview.
if (url.startsWith('chrome://theme'))
return url + '@2x';
return url;
},
});