mock-imagecapture.js (9030B)
1 import {BackgroundBlurMode, FillLightMode, ImageCapture, ImageCaptureReceiver, MeteringMode, RedEyeReduction} from '/gen/media/capture/mojom/image_capture.mojom.m.js'; 2 3 self.ImageCaptureTest = (() => { 4 // Class that mocks ImageCapture interface defined in 5 // https://cs.chromium.org/chromium/src/media/capture/mojom/image_capture.mojom 6 class MockImageCapture { 7 constructor() { 8 this.interceptor_ = 9 new MojoInterfaceInterceptor(ImageCapture.$interfaceName); 10 this.interceptor_.oninterfacerequest = 11 e => this.receiver_.$.bindHandle(e.handle); 12 this.interceptor_.start(); 13 14 this.state_ = { 15 state: { 16 supportedWhiteBalanceModes: [ 17 MeteringMode.SINGLE_SHOT, 18 MeteringMode.CONTINUOUS 19 ], 20 currentWhiteBalanceMode: MeteringMode.CONTINUOUS, 21 supportedExposureModes: [ 22 MeteringMode.MANUAL, 23 MeteringMode.SINGLE_SHOT, 24 MeteringMode.CONTINUOUS 25 ], 26 currentExposureMode: MeteringMode.MANUAL, 27 supportedFocusModes: [ 28 MeteringMode.MANUAL, 29 MeteringMode.SINGLE_SHOT 30 ], 31 currentFocusMode: MeteringMode.MANUAL, 32 pointsOfInterest: [{ 33 x: 0.4, 34 y: 0.6 35 }], 36 37 exposureCompensation: { 38 min: -200.0, 39 max: 200.0, 40 current: 33.0, 41 step: 33.0 42 }, 43 exposureTime: { 44 min: 100.0, 45 max: 100000.0, 46 current: 1000.0, 47 step: 100.0 48 }, 49 colorTemperature: { 50 min: 2500.0, 51 max: 6500.0, 52 current: 6000.0, 53 step: 1000.0 54 }, 55 iso: { 56 min: 100.0, 57 max: 12000.0, 58 current: 400.0, 59 step: 1.0 60 }, 61 62 brightness: { 63 min: 1.0, 64 max: 10.0, 65 current: 5.0, 66 step: 1.0 67 }, 68 contrast: { 69 min: 2.0, 70 max: 9.0, 71 current: 5.0, 72 step: 1.0 73 }, 74 saturation: { 75 min: 3.0, 76 max: 8.0, 77 current: 6.0, 78 step: 1.0 79 }, 80 sharpness: { 81 min: 4.0, 82 max: 7.0, 83 current: 7.0, 84 step: 1.0 85 }, 86 87 focusDistance: { 88 min: 1.0, 89 max: 10.0, 90 current: 3.0, 91 step: 1.0 92 }, 93 94 pan: { 95 min: 0.0, 96 max: 10.0, 97 current: 5.0, 98 step: 2.0 99 }, 100 101 tilt: { 102 min: 0.0, 103 max: 10.0, 104 current: 5.0, 105 step: 2.0 106 }, 107 108 zoom: { 109 min: 0.0, 110 max: 10.0, 111 current: 5.0, 112 step: 5.0 113 }, 114 115 supportsTorch: true, 116 torch: false, 117 118 redEyeReduction: RedEyeReduction.CONTROLLABLE, 119 height: { 120 min: 240.0, 121 max: 2448.0, 122 current: 240.0, 123 step: 2.0 124 }, 125 width: { 126 min: 320.0, 127 max: 3264.0, 128 current: 320.0, 129 step: 3.0 130 }, 131 fillLightMode: [FillLightMode.AUTO, FillLightMode.FLASH], 132 133 supportedBackgroundBlurModes: [ 134 BackgroundBlurMode.OFF, 135 BackgroundBlurMode.BLUR 136 ], 137 backgroundBlurMode: BackgroundBlurMode.OFF, 138 139 supportedFaceFramingModes: [], 140 141 supportedEyeGazeCorrectionModes: [], 142 143 supportedBackgroundSegmentationMaskStates: [], 144 } 145 }; 146 this.panTiltZoomPermissionStatus_ = null; 147 this.settings_ = null; 148 this.receiver_ = new ImageCaptureReceiver(this); 149 } 150 151 reset() { 152 this.receiver_.$.close(); 153 this.interceptor_.stop(); 154 } 155 156 async getPhotoState(source_id) { 157 const shouldKeepPanTiltZoom = await this.isPanTiltZoomPermissionGranted(); 158 if (shouldKeepPanTiltZoom) 159 return Promise.resolve(this.state_); 160 161 const newState = {...this.state_}; 162 newState.state.pan = {}; 163 newState.state.tilt = {}; 164 newState.state.zoom = {}; 165 return Promise.resolve(newState); 166 } 167 168 async setPhotoOptions(source_id, settings) { 169 const isAllowedToControlPanTiltZoom = await this.isPanTiltZoomPermissionGranted(); 170 if (!isAllowedToControlPanTiltZoom && 171 (settings.hasPan || settings.hasTilt || settings.hasZoom)) { 172 return Promise.resolve({ success: false }); 173 } 174 this.settings_ = settings; 175 if (settings.hasIso) 176 this.state_.state.iso.current = settings.iso; 177 if (settings.hasHeight) 178 this.state_.state.height.current = settings.height; 179 if (settings.hasWidth) 180 this.state_.state.width.current = settings.width; 181 if (settings.hasPan) 182 this.state_.state.pan.current = settings.pan; 183 if (settings.hasTilt) 184 this.state_.state.tilt.current = settings.tilt; 185 if (settings.hasZoom) 186 this.state_.state.zoom.current = settings.zoom; 187 if (settings.hasFocusMode) 188 this.state_.state.currentFocusMode = settings.focusMode; 189 if (settings.hasFocusDistance) 190 this.state_.state.focusDistance.current = settings.focusDistance; 191 192 if (settings.pointsOfInterest.length > 0) { 193 this.state_.state.pointsOfInterest = 194 settings.pointsOfInterest; 195 } 196 197 if (settings.hasExposureMode) 198 this.state_.state.currentExposureMode = settings.exposureMode; 199 200 if (settings.hasExposureCompensation) { 201 this.state_.state.exposureCompensation.current = 202 settings.exposureCompensation; 203 } 204 if (settings.hasExposureTime) { 205 this.state_.state.exposureTime.current = 206 settings.exposureTime; 207 } 208 if (settings.hasWhiteBalanceMode) { 209 this.state_.state.currentWhiteBalanceMode = 210 settings.whiteBalanceMode; 211 } 212 if (settings.hasFillLightMode) 213 this.state_.state.fillLightMode = [settings.fillLightMode]; 214 if (settings.hasRedEyeReduction) 215 this.state_.state.redEyeReduction = settings.redEyeReduction; 216 if (settings.hasColorTemperature) { 217 this.state_.state.colorTemperature.current = 218 settings.colorTemperature; 219 } 220 if (settings.hasBrightness) 221 this.state_.state.brightness.current = settings.brightness; 222 if (settings.hasContrast) 223 this.state_.state.contrast.current = settings.contrast; 224 if (settings.hasSaturation) 225 this.state_.state.saturation.current = settings.saturation; 226 if (settings.hasSharpness) 227 this.state_.state.sharpness.current = settings.sharpness; 228 229 if (settings.hasTorch) 230 this.state_.state.torch = settings.torch; 231 232 if (settings.hasBackgroundBlurMode) 233 this.state_.state.backgroundBlurMode = [settings.backgroundBlurMode]; 234 235 return Promise.resolve({ 236 success: true 237 }); 238 } 239 240 takePhoto(source_id) { 241 return Promise.resolve({ 242 blob: { 243 mimeType: 'image/cat', 244 data: new Array(2) 245 } 246 }); 247 } 248 249 async isPanTiltZoomPermissionGranted() { 250 if (!this.panTiltZoomPermissionStatus_) { 251 this.panTiltZoomPermissionStatus_ = await navigator.permissions.query({ 252 name: "camera", 253 panTiltZoom: true 254 }); 255 } 256 return this.panTiltZoomPermissionStatus_.state == "granted"; 257 } 258 259 state() { 260 return this.state_.state; 261 } 262 263 turnOffBackgroundBlurMode() { 264 this.state_.state.backgroundBlurMode = BackgroundBlurMode.OFF; 265 } 266 turnOnBackgroundBlurMode() { 267 this.state_.state.backgroundBlurMode = BackgroundBlurMode.BLUR; 268 } 269 turnOffSupportedBackgroundBlurModes() { 270 this.state_.state.supportedBackgroundBlurModes = [BackgroundBlurMode.OFF]; 271 } 272 turnOnSupportedBackgroundBlurModes() { 273 this.state_.state.supportedBackgroundBlurModes = [BackgroundBlurMode.BLUR]; 274 } 275 276 options() { 277 return this.settings_; 278 } 279 } 280 281 let testInternal = { 282 initialized: false, 283 mockImageCapture: null 284 } 285 286 class ImageCaptureTestChromium { 287 288 constructor() { 289 Object.freeze(this); // Make it immutable. 290 } 291 292 initialize() { 293 if (testInternal.initialized) 294 throw new Error('Call reset() before initialize().'); 295 296 testInternal.mockImageCapture = new MockImageCapture; 297 testInternal.initialized = true; 298 } 299 // Resets state of image capture mocks between test runs. 300 async reset() { 301 if (!testInternal.initialized) 302 throw new Error('Call initialize() before reset().'); 303 testInternal.mockImageCapture.reset(); 304 testInternal.mockImageCapture = null; 305 testInternal.initialized = false; 306 307 await new Promise(resolve => setTimeout(resolve, 0)); 308 } 309 mockImageCapture() { 310 return testInternal.mockImageCapture; 311 } 312 } 313 314 return ImageCaptureTestChromium; 315 })();