| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 var vrShellUi = (function() { | 5 var vrShellUi = (function() { |
| 6 'use strict'; | 6 'use strict'; |
| 7 | 7 |
| 8 let ui = new scene.Scene(); | 8 let ui = new scene.Scene(); |
| 9 let uiManager; | 9 let uiManager; |
| 10 let nativeCommandHandler; | 10 let nativeCommandHandler; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 /** @const */ this.CSS_HEIGHT_PIXELS = 640.0; | 36 /** @const */ this.CSS_HEIGHT_PIXELS = 640.0; |
| 37 /** @const */ this.DPR = 1.2; | 37 /** @const */ this.DPR = 1.2; |
| 38 /** @const */ this.MENU_MODE_SCREEN_DISTANCE = 1.2; | 38 /** @const */ this.MENU_MODE_SCREEN_DISTANCE = 1.2; |
| 39 /** @const */ this.MENU_MODE_SCREEN_HEIGHT = 0.5; | 39 /** @const */ this.MENU_MODE_SCREEN_HEIGHT = 0.5; |
| 40 /** @const */ this.MENU_MODE_SCREEN_ELEVATION = 0.1; | 40 /** @const */ this.MENU_MODE_SCREEN_ELEVATION = 0.1; |
| 41 /** @const */ this.BACKGROUND_DISTANCE_MULTIPLIER = 1.414; | 41 /** @const */ this.BACKGROUND_DISTANCE_MULTIPLIER = 1.414; |
| 42 | 42 |
| 43 this.menuMode = false; | 43 this.menuMode = false; |
| 44 this.fullscreen = false; | 44 this.fullscreen = false; |
| 45 | 45 |
| 46 let element = new api.UiElement(0, 0, 0, 0); | 46 this.uiElement = new DomUiElement('#content-quad-element'); |
| 47 element.setFill(new api.Content()); | 47 this.elementId = this.uiElement.uiElementId; |
| 48 element.setVisible(false); | 48 |
| 49 element.setSize( | 49 let update = new api.UiElementUpdate(); |
| 50 this.SCREEN_HEIGHT * this.SCREEN_RATIO, this.SCREEN_HEIGHT); | 50 update.setFill(new api.Content()); |
| 51 element.setTranslation(0, 0, -this.BROWSING_SCREEN_DISTANCE); | 51 update.setVisible(false); |
| 52 this.elementId = ui.addElement(element); | 52 ui.updateElement(this.elementId, update); |
| 53 | 53 |
| 54 // Place an invisible but hittable plane behind the content quad, to keep | 54 // Place an invisible but hittable plane behind the content quad, to keep |
| 55 // the reticle roughly planar with the content if near content. | 55 // the reticle roughly planar with the content if near content. |
| 56 let backPlane = new api.UiElement(0, 0, 0, 0); | 56 let backPlane = new api.UiElement(0, 0, 0, 0); |
| 57 backPlane.setVisible(false); | 57 backPlane.setVisible(false); |
| 58 backPlane.setHitTestable(true); | 58 backPlane.setHitTestable(true); |
| 59 backPlane.setSize(1000, 1000); | 59 backPlane.setSize(1000, 1000); |
| 60 backPlane.setTranslation(0, 0, -0.01); | 60 backPlane.setTranslation(0, 0, -0.01); |
| 61 backPlane.setParentId(this.elementId); | 61 backPlane.setParentId(this.elementId); |
| 62 ui.addElement(backPlane); | 62 ui.addElement(backPlane); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 85 } | 85 } |
| 86 | 86 |
| 87 setFullscreen(enabled) { | 87 setFullscreen(enabled) { |
| 88 if (this.fullscreen == enabled) | 88 if (this.fullscreen == enabled) |
| 89 return; | 89 return; |
| 90 this.fullscreen = enabled; | 90 this.fullscreen = enabled; |
| 91 this.updateState() | 91 this.updateState() |
| 92 } | 92 } |
| 93 | 93 |
| 94 updateState() { | 94 updateState() { |
| 95 // Defaults content quad parameters. | 95 // Set style according to mode. |
| 96 let y = 0; | 96 this.uiElement.domElement.classList.remove('menu'); |
| 97 let distance = this.BROWSING_SCREEN_DISTANCE; | 97 this.uiElement.domElement.classList.remove('fullscreen'); |
| 98 let height = this.SCREEN_HEIGHT; | |
| 99 | |
| 100 // Mode-specific overrides. | |
| 101 if (this.menuMode) { | 98 if (this.menuMode) { |
| 102 y = this.MENU_MODE_SCREEN_ELEVATION; | 99 this.uiElement.domElement.classList.add('menu'); |
| 103 distance = this.MENU_MODE_SCREEN_DISTANCE; | |
| 104 height = this.MENU_MODE_SCREEN_HEIGHT; | |
| 105 } else if (this.fullscreen) { | 100 } else if (this.fullscreen) { |
| 106 distance = this.FULLSCREEN_DISTANCE; | 101 this.uiElement.domElement.classList.add('fullscreen'); |
| 107 } | 102 } |
| 108 | 103 |
| 109 let anim; | 104 //ui.setBackgroundDistance(distance * this.BACKGROUND_DISTANCE_MULTIPLIER)
; |
| 110 anim = new api.Animation(this.elementId, ANIM_DURATION); | |
| 111 anim.setTranslation(0, y, -distance); | |
| 112 ui.addAnimation(anim); | |
| 113 anim = new api.Animation(this.elementId, ANIM_DURATION); | |
| 114 anim.setSize(height * this.SCREEN_RATIO, height); | |
| 115 ui.addAnimation(anim); | |
| 116 | |
| 117 ui.setBackgroundDistance(distance * this.BACKGROUND_DISTANCE_MULTIPLIER); | |
| 118 } | 105 } |
| 119 | 106 |
| 120 // TODO(crbug/643815): Add a method setting aspect ratio (and possible | 107 // TODO(crbug/643815): Add a method setting aspect ratio (and possible |
| 121 // animation of changing it). | 108 // animation of changing it). |
| 122 | 109 |
| 123 getElementId() { | 110 getElementId() { |
| 124 return this.elementId; | 111 return this.elementId; |
| 125 } | 112 } |
| 126 }; | 113 }; |
| 127 | 114 |
| 128 class DomUiElement { | 115 class DomUiElement { |
| 129 constructor(domId) { | 116 constructor(domId) { |
| 130 let domElement = document.querySelector(domId); | 117 let domElement = document.querySelector(domId); |
| 131 | 118 |
| 119 // Attach a mutation observer to catch our custom scene style changes. |
| 120 this.observer = new MutationObserver(function(mutations) { |
| 121 let update = new api.UiElementUpdate(); |
| 122 let modifications = false; |
| 123 |
| 124 mutations.forEach(function(update, mutation) { |
| 125 modifications = modifications || this.parseCustomStyle(mutation.target
, update); |
| 126 }.bind(this, update)); |
| 127 |
| 128 if (modifications) { |
| 129 ui.updateElement(this.uiElementId, update); |
| 130 } |
| 131 }.bind(this)); |
| 132 var config = { |
| 133 attributes: true, |
| 134 subtree: true, |
| 135 //attributeFilter: ['style'] // TODO: Better filtering? |
| 136 }; |
| 137 this.observer.observe(domElement, config); |
| 138 |
| 132 // Pull copy rectangle from the position of the element. | 139 // Pull copy rectangle from the position of the element. |
| 133 let rect = domElement.getBoundingClientRect(); | 140 let rect = domElement.getBoundingClientRect(); |
| 134 let pixelX = Math.floor(rect.left); | 141 let pixelX = Math.floor(rect.left); |
| 135 let pixelY = Math.floor(rect.top); | 142 let pixelY = Math.floor(rect.top); |
| 136 let pixelWidth = Math.ceil(rect.right) - pixelX; | 143 let pixelWidth = Math.ceil(rect.right) - pixelX; |
| 137 let pixelHeight = Math.ceil(rect.bottom) - pixelY; | 144 let pixelHeight = Math.ceil(rect.bottom) - pixelY; |
| 138 | 145 |
| 139 let element = new api.UiElement(pixelX, pixelY, pixelWidth, pixelHeight); | 146 let element = new api.UiElement(pixelX, pixelY, pixelWidth, pixelHeight); |
| 140 element.setSize(pixelWidth / 1000, pixelHeight / 1000); | 147 element.setSize(pixelWidth / 1000, pixelHeight / 1000); |
| 141 | 148 |
| 142 // Pull additional custom properties from CSS. | 149 // Grab initial custom scene styling. |
| 143 let style = window.getComputedStyle(domElement); | 150 this.parseCustomStyle(domElement, element); |
| 144 this.translationX = getStyleFloat(style, '--tranX'); | 151 var items = domElement.getElementsByTagName("*"); |
| 145 this.translationY = getStyleFloat(style, '--tranY'); | 152 for (var i = 0; i < items.length; i++) { |
| 146 this.translationZ = getStyleFloat(style, '--tranZ'); | 153 this.parseCustomStyle(items[i], element); |
| 147 element.setTranslation( | 154 } |
| 148 this.translationX, this.translationY, this.translationZ); | |
| 149 | 155 |
| 150 this.uiElementId = ui.addElement(element); | 156 this.uiElementId = ui.addElement(element); |
| 151 this.uiAnimationId = -1; | 157 this.uiAnimationId = -1; |
| 152 this.domElement = domElement; | 158 this.domElement = domElement; |
| 153 } | 159 } |
| 160 |
| 161 parseCustomStyle(element, update) { |
| 162 let propertyMap = { |
| 163 '--tranX': 'translationX', |
| 164 '--tranY': 'translationY', |
| 165 '--tranZ': 'translationZ', |
| 166 '--sizeX': 'sizeX', |
| 167 '--sizeY': 'sizeY', |
| 168 '--scaleX': 'scaleX', |
| 169 '--scaleY': 'scaleY', |
| 170 '--scaleZ': 'scaleZ', |
| 171 '--rotationX': 'rotationX', |
| 172 '--rotationY': 'rotationY', |
| 173 '--rotationZ': 'rotationZ', |
| 174 '--rotationAngle': 'rotationAngle', |
| 175 '--opacity': 'opacity', |
| 176 }; |
| 177 |
| 178 // For each custom property we recognize, apply its value to the |
| 179 // corresponding UI element property. |
| 180 let cs = window.getComputedStyle(element); |
| 181 let keys = Object.keys(propertyMap); |
| 182 let len = keys.length; |
| 183 let modifications = false; |
| 184 for (var i = 0; i < len; i++) { |
| 185 let item = keys[i]; |
| 186 |
| 187 let value = parseFloat(cs.getPropertyValue(item)); |
| 188 if (isNaN(value)) |
| 189 continue; |
| 190 update.properties[propertyMap[item]] = value; |
| 191 modifications = true; |
| 192 } |
| 193 return modifications; |
| 194 } |
| 154 }; | 195 }; |
| 155 | 196 |
| 156 class RoundButton extends DomUiElement { | 197 class RoundButton extends DomUiElement { |
| 157 constructor(domId, callback) { | 198 constructor(domId, callback) { |
| 158 super(domId); | 199 super(domId); |
| 159 | 200 |
| 160 let button = this.domElement.querySelector('.button'); | 201 let button = this.domElement.querySelector('.button'); |
| 161 button.addEventListener('mouseenter', this.onMouseEnter.bind(this)); | 202 button.addEventListener('mouseenter', this.onMouseEnter.bind(this)); |
| 162 button.addEventListener('mouseleave', this.onMouseLeave.bind(this)); | 203 button.addEventListener('mouseleave', this.onMouseLeave.bind(this)); |
| 163 button.addEventListener('click', callback); | 204 button.addEventListener('click', callback); |
| (...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 !this.loading && this.visibilityTimeout > 0 && !this.visibilityTimer; | 540 !this.loading && this.visibilityTimeout > 0 && !this.visibilityTimer; |
| 500 if (shouldBeHidden != this.hidden) { | 541 if (shouldBeHidden != this.hidden) { |
| 501 // Make the box fade away if it's disappearing. | 542 // Make the box fade away if it's disappearing. |
| 502 this.hidden = shouldBeHidden; | 543 this.hidden = shouldBeHidden; |
| 503 | 544 |
| 504 // Fade-out or fade-in the box. | 545 // Fade-out or fade-in the box. |
| 505 let opacityAnimation = | 546 let opacityAnimation = |
| 506 new api.Animation(this.domUiElement.uiElementId, this.fadeTimeMs); | 547 new api.Animation(this.domUiElement.uiElementId, this.fadeTimeMs); |
| 507 opacityAnimation.setOpacity(this.hidden ? 0.0 : this.opacity); | 548 opacityAnimation.setOpacity(this.hidden ? 0.0 : this.opacity); |
| 508 ui.addAnimation(opacityAnimation); | 549 ui.addAnimation(opacityAnimation); |
| 509 | |
| 510 // Drop the position as it fades, or raise the position if appearing. | |
| 511 let yOffset = this.hidden ? this.fadeYOffset : 0; | |
| 512 let positionAnimation = | |
| 513 new api.Animation(this.domUiElement.uiElementId, this.fadeTimeMs); | |
| 514 positionAnimation.setTranslation( | |
| 515 this.domUiElement.translationX, | |
| 516 this.domUiElement.translationY + yOffset, | |
| 517 this.domUiElement.translationZ); | |
| 518 ui.addAnimation(positionAnimation); | |
| 519 } | 550 } |
| 520 | 551 |
| 521 ui.flush(); | 552 ui.flush(); |
| 522 } | 553 } |
| 523 | 554 |
| 524 setNativeVisibility(visible) { | 555 setNativeVisibility(visible) { |
| 525 if (visible == this.nativeState.visible) { | 556 if (visible == this.nativeState.visible) { |
| 526 return; | 557 return; |
| 527 } | 558 } |
| 528 this.nativeState.visible = visible; | 559 this.nativeState.visible = visible; |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 796 setEnabled(enabled) { | 827 setEnabled(enabled) { |
| 797 let visibilityUpdate = new api.UiElementUpdate(); | 828 let visibilityUpdate = new api.UiElementUpdate(); |
| 798 visibilityUpdate.setVisible(enabled); | 829 visibilityUpdate.setVisible(enabled); |
| 799 ui.updateElement(this.tabContainerElement.uiElementId, visibilityUpdate); | 830 ui.updateElement(this.tabContainerElement.uiElementId, visibilityUpdate); |
| 800 } | 831 } |
| 801 }; | 832 }; |
| 802 | 833 |
| 803 class UiManager { | 834 class UiManager { |
| 804 constructor() { | 835 constructor() { |
| 805 this.mode = api.Mode.UNKNOWN; | 836 this.mode = api.Mode.UNKNOWN; |
| 806 this.menuMode = false; | 837 // this.menuMode = false; |
| 838 this.menuMode = true; |
| 807 this.fullscreen = false; | 839 this.fullscreen = false; |
| 808 | 840 |
| 809 this.background = new Background(); | 841 this.background = new Background(); |
| 810 this.contentQuad = new ContentQuad(); | 842 this.contentQuad = new ContentQuad(); |
| 811 let contentId = this.contentQuad.getElementId(); | 843 let contentId = this.contentQuad.getElementId(); |
| 812 | 844 |
| 813 this.controls = new Controls(contentId); | 845 this.controls = new Controls(contentId); |
| 814 this.secureOriginWarnings = new SecureOriginWarnings(); | 846 this.secureOriginWarnings = new SecureOriginWarnings(); |
| 815 this.urlIndicator = new UrlIndicator(); | 847 this.urlIndicator = new UrlIndicator(); |
| 816 this.omnibox = new Omnibox(); | 848 this.omnibox = new Omnibox(); |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 966 nativeCommandHandler.handleCommand(dict); | 998 nativeCommandHandler.handleCommand(dict); |
| 967 } | 999 } |
| 968 | 1000 |
| 969 return { | 1001 return { |
| 970 initialize: initialize, | 1002 initialize: initialize, |
| 971 command: command, | 1003 command: command, |
| 972 }; | 1004 }; |
| 973 })(); | 1005 })(); |
| 974 | 1006 |
| 975 window.addEventListener('load', vrShellUi.initialize); | 1007 window.addEventListener('load', vrShellUi.initialize); |
| OLD | NEW |