| 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 #include "modules/vr/VRDisplay.h" | 5 #include "modules/vr/VRDisplay.h" |
| 6 | 6 |
| 7 #include "core/css/StylePropertySet.h" | 7 #include "core/css/StylePropertySet.h" |
| 8 #include "core/dom/DOMException.h" | 8 #include "core/dom/DOMException.h" |
| 9 #include "core/dom/DocumentUserGestureToken.h" | 9 #include "core/dom/DocumentUserGestureToken.h" |
| 10 #include "core/dom/FrameRequestCallback.h" | 10 #include "core/dom/FrameRequestCallback.h" |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 254 forceExitPresent(); | 254 forceExitPresent(); |
| 255 DOMException* exception = | 255 DOMException* exception = |
| 256 DOMException::create(InvalidStateError, "Invalid number of layers."); | 256 DOMException::create(InvalidStateError, "Invalid number of layers."); |
| 257 resolver->reject(exception); | 257 resolver->reject(exception); |
| 258 ReportPresentationResult(PresentationResult::InvalidNumberOfLayers); | 258 ReportPresentationResult(PresentationResult::InvalidNumberOfLayers); |
| 259 return promise; | 259 return promise; |
| 260 } | 260 } |
| 261 | 261 |
| 262 // If what we were given has an invalid source, need to exit fullscreen with | 262 // If what we were given has an invalid source, need to exit fullscreen with |
| 263 // previous, valid source, so delay m_layer reassignment | 263 // previous, valid source, so delay m_layer reassignment |
| 264 if (!layers[0].source()) { | 264 if (layers[0].source().isNull()) { |
| 265 forceExitPresent(); | 265 forceExitPresent(); |
| 266 DOMException* exception = | 266 DOMException* exception = |
| 267 DOMException::create(InvalidStateError, "Invalid layer source."); | 267 DOMException::create(InvalidStateError, "Invalid layer source."); |
| 268 resolver->reject(exception); | 268 resolver->reject(exception); |
| 269 ReportPresentationResult(PresentationResult::InvalidLayerSource); | 269 ReportPresentationResult(PresentationResult::InvalidLayerSource); |
| 270 return promise; | 270 return promise; |
| 271 } | 271 } |
| 272 m_layer = layers[0]; | 272 m_layer = layers[0]; |
| 273 | 273 |
| 274 CanvasRenderingContext* renderingContext = | 274 CanvasRenderingContext* renderingContext; |
| 275 m_layer.source()->renderingContext(); | 275 if (m_layer.source().isHTMLCanvasElement()) { |
| 276 renderingContext = |
| 277 m_layer.source().getAsHTMLCanvasElement()->renderingContext(); |
| 278 } else { |
| 279 DCHECK(m_layer.source().isOffscreenCanvas()); |
| 280 renderingContext = |
| 281 m_layer.source().getAsOffscreenCanvas()->renderingContext(); |
| 282 } |
| 276 | 283 |
| 277 if (!renderingContext || !renderingContext->is3d()) { | 284 if (!renderingContext || !renderingContext->is3d()) { |
| 278 forceExitPresent(); | 285 forceExitPresent(); |
| 279 DOMException* exception = DOMException::create( | 286 DOMException* exception = DOMException::create( |
| 280 InvalidStateError, "Layer source must have a WebGLRenderingContext"); | 287 InvalidStateError, "Layer source must have a WebGLRenderingContext"); |
| 281 resolver->reject(exception); | 288 resolver->reject(exception); |
| 282 ReportPresentationResult( | 289 ReportPresentationResult( |
| 283 PresentationResult::LayerSourceMissingWebGLContext); | 290 PresentationResult::LayerSourceMissingWebGLContext); |
| 284 return promise; | 291 return promise; |
| 285 } | 292 } |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 379 InvalidStateError, | 386 InvalidStateError, |
| 380 "VR Presentation not implemented for this VRDisplay."); | 387 "VR Presentation not implemented for this VRDisplay."); |
| 381 while (!m_pendingPresentResolvers.isEmpty()) { | 388 while (!m_pendingPresentResolvers.isEmpty()) { |
| 382 ScriptPromiseResolver* resolver = m_pendingPresentResolvers.takeFirst(); | 389 ScriptPromiseResolver* resolver = m_pendingPresentResolvers.takeFirst(); |
| 383 resolver->reject(exception); | 390 resolver->reject(exception); |
| 384 } | 391 } |
| 385 ReportPresentationResult( | 392 ReportPresentationResult( |
| 386 PresentationResult::PresentationNotSupportedByDisplay); | 393 PresentationResult::PresentationNotSupportedByDisplay); |
| 387 return; | 394 return; |
| 388 } else { | 395 } else { |
| 389 // TODO(klausw,crbug.com/655722): Need a proper VR compositor, but | 396 if (m_layer.source().isHTMLCanvasElement()) { |
| 390 // for the moment on mobile we'll just make the canvas fullscreen | 397 HTMLCanvasElement* canvas = m_layer.source().getAsHTMLCanvasElement(); |
| 391 // so that VrShell can pick it up through the standard (high | 398 // TODO(klausw,crbug.com/655722): Need a proper VR compositor, but |
| 392 // latency) compositing path. | 399 // for the moment on mobile we'll just make the canvas fullscreen |
| 393 auto canvas = m_layer.source(); | 400 // so that VrShell can pick it up through the standard (high |
| 394 auto inlineStyle = canvas->inlineStyle(); | 401 // latency) compositing path. auto canvas = |
| 395 if (inlineStyle) { | 402 // m_layer.source().getAsHTMLCanvasElement(); |
| 396 // THREE.js's VREffect sets explicit style.width/height on its rendering | 403 auto inlineStyle = canvas->inlineStyle(); |
| 397 // canvas based on the non-fullscreen window dimensions, and it keeps | 404 if (inlineStyle) { |
| 398 // those unchanged when presenting. Unfortunately it appears that a | 405 // THREE.js's VREffect sets explicit style.width/height on its rendering |
| 399 // fullscreened canvas just gets centered if it has explicitly set a | 406 // canvas based on the non-fullscreen window dimensions, and it keeps |
| 400 // size smaller than the fullscreen dimensions. Manually set size to | 407 // those unchanged when presenting. Unfortunately it appears that a |
| 401 // 100% in this case and restore it when exiting fullscreen. This is a | 408 // fullscreened canvas just gets centered if it has explicitly set a |
| 402 // stopgap measure since THREE.js's usage appears legal according to the | 409 // size smaller than the fullscreen dimensions. Manually set size to |
| 403 // WebVR API spec. This will no longer be necessary once we can get rid | 410 // 100% in this case and restore it when exiting fullscreen. This is a |
| 404 // of this fullscreen hack. | 411 // stopgap measure since THREE.js's usage appears legal according to the |
| 405 m_fullscreenOrigWidth = inlineStyle->getPropertyValue(CSSPropertyWidth); | 412 // WebVR API spec. This will no longer be necessary once we can get rid |
| 406 if (!m_fullscreenOrigWidth.isNull()) { | 413 // of this fullscreen hack. |
| 407 canvas->setInlineStyleProperty(CSSPropertyWidth, "100%"); | 414 m_fullscreenOrigWidth = inlineStyle->getPropertyValue(CSSPropertyWidth); |
| 415 if (!m_fullscreenOrigWidth.isNull()) { |
| 416 canvas->setInlineStyleProperty(CSSPropertyWidth, "100%"); |
| 417 } |
| 418 m_fullscreenOrigHeight = |
| 419 inlineStyle->getPropertyValue(CSSPropertyHeight); |
| 420 if (!m_fullscreenOrigHeight.isNull()) { |
| 421 canvas->setInlineStyleProperty(CSSPropertyHeight, "100%"); |
| 422 } |
| 423 } else { |
| 424 m_fullscreenOrigWidth = String(); |
| 425 m_fullscreenOrigHeight = String(); |
| 408 } | 426 } |
| 409 m_fullscreenOrigHeight = inlineStyle->getPropertyValue(CSSPropertyHeight); | 427 |
| 410 if (!m_fullscreenOrigHeight.isNull()) { | 428 if (doc) { |
| 411 canvas->setInlineStyleProperty(CSSPropertyHeight, "100%"); | 429 // Since the callback for requestPresent is asynchronous, we've lost our |
| 430 // UserGestureToken, and need to create a new one to enter fullscreen. |
| 431 gestureIndicator = WTF::wrapUnique( |
| 432 new UserGestureIndicator(DocumentUserGestureToken::create( |
| 433 doc, UserGestureToken::Status::PossiblyExistingGesture))); |
| 412 } | 434 } |
| 435 Fullscreen::requestFullscreen(*canvas); |
| 436 |
| 437 // Check to see if the canvas is still the current fullscreen |
| 438 // element once every 2 seconds. |
| 439 m_fullscreenCheckTimer.startRepeating(2.0, BLINK_FROM_HERE); |
| 440 m_reenteredFullscreen = false; |
| 413 } else { | 441 } else { |
| 414 m_fullscreenOrigWidth = String(); | 442 DCHECK(m_layer.source().isOffscreenCanvas()); |
| 415 m_fullscreenOrigHeight = String(); | 443 // TODO(junov, crbug.com/695497): Implement OffscreenCanvas presentation |
| 444 forceExitPresent(); |
| 445 DOMException* exception = DOMException::create( |
| 446 InvalidStateError, "OffscreenCanvas presentation not implemented."); |
| 447 while (!m_pendingPresentResolvers.isEmpty()) { |
| 448 ScriptPromiseResolver* resolver = m_pendingPresentResolvers.takeFirst(); |
| 449 resolver->reject(exception); |
| 450 } |
| 451 ReportPresentationResult( |
| 452 PresentationResult::PresentationNotSupportedByDisplay); |
| 453 return; |
| 416 } | 454 } |
| 417 | |
| 418 if (doc) { | |
| 419 // Since the callback for requestPresent is asynchronous, we've lost our | |
| 420 // UserGestureToken, and need to create a new one to enter fullscreen. | |
| 421 gestureIndicator = WTF::wrapUnique( | |
| 422 new UserGestureIndicator(DocumentUserGestureToken::create( | |
| 423 doc, UserGestureToken::Status::PossiblyExistingGesture))); | |
| 424 } | |
| 425 Fullscreen::requestFullscreen(*canvas); | |
| 426 | |
| 427 // Check to see if the canvas is still the current fullscreen | |
| 428 // element once every 2 seconds. | |
| 429 m_fullscreenCheckTimer.startRepeating(2.0, BLINK_FROM_HERE); | |
| 430 m_reenteredFullscreen = false; | |
| 431 } | 455 } |
| 432 | 456 |
| 433 if (doc) { | 457 if (doc) { |
| 434 Platform::current()->recordRapporURL("VR.WebVR.PresentSuccess", | 458 Platform::current()->recordRapporURL("VR.WebVR.PresentSuccess", |
| 435 WebURL(doc->url())); | 459 WebURL(doc->url())); |
| 436 } | 460 } |
| 437 | 461 |
| 438 m_isPresenting = true; | 462 m_isPresenting = true; |
| 439 ReportPresentationResult(PresentationResult::Success); | 463 ReportPresentationResult(PresentationResult::Success); |
| 440 | 464 |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 603 } | 627 } |
| 604 | 628 |
| 605 void VRDisplay::onDisconnected() { | 629 void VRDisplay::onDisconnected() { |
| 606 m_navigatorVR->enqueueVREvent(VRDisplayEvent::create( | 630 m_navigatorVR->enqueueVREvent(VRDisplayEvent::create( |
| 607 EventTypeNames::vrdisplaydisconnect, true, false, this, "disconnect")); | 631 EventTypeNames::vrdisplaydisconnect, true, false, this, "disconnect")); |
| 608 } | 632 } |
| 609 | 633 |
| 610 void VRDisplay::stopPresenting() { | 634 void VRDisplay::stopPresenting() { |
| 611 if (m_isPresenting) { | 635 if (m_isPresenting) { |
| 612 if (!m_capabilities->hasExternalDisplay()) { | 636 if (!m_capabilities->hasExternalDisplay()) { |
| 613 auto canvas = m_layer.source(); | 637 if (m_layer.source().isHTMLCanvasElement()) { |
| 614 Fullscreen::fullyExitFullscreen(canvas->document()); | 638 auto canvas = m_layer.source().getAsHTMLCanvasElement(); |
| 615 m_fullscreenCheckTimer.stop(); | 639 Fullscreen::fullyExitFullscreen(canvas->document()); |
| 616 if (!m_fullscreenOrigWidth.isNull()) { | 640 m_fullscreenCheckTimer.stop(); |
| 617 canvas->setInlineStyleProperty(CSSPropertyWidth, m_fullscreenOrigWidth); | 641 if (!m_fullscreenOrigWidth.isNull()) { |
| 618 m_fullscreenOrigWidth = String(); | 642 canvas->setInlineStyleProperty(CSSPropertyWidth, |
| 619 } | 643 m_fullscreenOrigWidth); |
| 620 if (!m_fullscreenOrigHeight.isNull()) { | 644 m_fullscreenOrigWidth = String(); |
| 621 canvas->setInlineStyleProperty(CSSPropertyWidth, | 645 } |
| 622 m_fullscreenOrigHeight); | 646 if (!m_fullscreenOrigHeight.isNull()) { |
| 623 m_fullscreenOrigHeight = String(); | 647 canvas->setInlineStyleProperty(CSSPropertyWidth, |
| 648 m_fullscreenOrigHeight); |
| 649 m_fullscreenOrigHeight = String(); |
| 650 } |
| 651 } else { |
| 652 // TODO(junov, crbug.com/695497): Implement for OffscreenCanvas |
| 624 } | 653 } |
| 625 } else { | 654 } else { |
| 626 // Can't get into this presentation mode, so nothing to do here. | 655 // Can't get into this presentation mode, so nothing to do here. |
| 627 } | 656 } |
| 628 m_isPresenting = false; | 657 m_isPresenting = false; |
| 629 OnPresentChange(); | 658 OnPresentChange(); |
| 630 } | 659 } |
| 631 | 660 |
| 632 m_renderingContext = nullptr; | 661 m_renderingContext = nullptr; |
| 633 m_contextGL = nullptr; | 662 m_contextGL = nullptr; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 685 if (!m_navigatorVR->isFocused()) | 714 if (!m_navigatorVR->isFocused()) |
| 686 return; | 715 return; |
| 687 m_display->GetVRVSyncProvider(mojo::MakeRequest(&m_vrVSyncProvider)); | 716 m_display->GetVRVSyncProvider(mojo::MakeRequest(&m_vrVSyncProvider)); |
| 688 if (m_pendingRaf && !m_displayBlurred) { | 717 if (m_pendingRaf && !m_displayBlurred) { |
| 689 m_vrVSyncProvider->GetVSync(convertToBaseCallback( | 718 m_vrVSyncProvider->GetVSync(convertToBaseCallback( |
| 690 WTF::bind(&VRDisplay::OnVSync, wrapWeakPersistent(this)))); | 719 WTF::bind(&VRDisplay::OnVSync, wrapWeakPersistent(this)))); |
| 691 } | 720 } |
| 692 } | 721 } |
| 693 | 722 |
| 694 void VRDisplay::onFullscreenCheck(TimerBase*) { | 723 void VRDisplay::onFullscreenCheck(TimerBase*) { |
| 724 DCHECK(m_layer.source().isHTMLCanvasElement()); |
| 695 if (!m_isPresenting) { | 725 if (!m_isPresenting) { |
| 696 m_fullscreenCheckTimer.stop(); | 726 m_fullscreenCheckTimer.stop(); |
| 697 return; | 727 return; |
| 698 } | 728 } |
| 699 // TODO: This is a temporary measure to track if fullscreen mode has been | 729 // TODO: This is a temporary measure to track if fullscreen mode has been |
| 700 // exited by the UA. If so we need to end VR presentation. Soon we won't | 730 // exited by the UA. If so we need to end VR presentation. Soon we won't |
| 701 // depend on the Fullscreen API to fake VR presentation, so this will | 731 // depend on the Fullscreen API to fake VR presentation, so this will |
| 702 // become unnessecary. Until that point, though, this seems preferable to | 732 // become unnessecary. Until that point, though, this seems preferable to |
| 703 // adding a bunch of notification plumbing to Fullscreen. | 733 // adding a bunch of notification plumbing to Fullscreen. |
| 704 if (!Fullscreen::isCurrentFullScreenElement(*m_layer.source())) { | 734 if (!Fullscreen::isCurrentFullScreenElement( |
| 735 *m_layer.source().getAsHTMLCanvasElement())) { |
| 705 // TODO(mthiesse): Due to asynchronous resizing, we might get kicked out of | 736 // TODO(mthiesse): Due to asynchronous resizing, we might get kicked out of |
| 706 // fullscreen when changing display parameters upon entering WebVR. So one | 737 // fullscreen when changing display parameters upon entering WebVR. So one |
| 707 // time only, we reenter fullscreen after having left it; otherwise we exit | 738 // time only, we reenter fullscreen after having left it; otherwise we exit |
| 708 // presentation. | 739 // presentation. |
| 709 if (m_reenteredFullscreen) { | 740 if (m_reenteredFullscreen) { |
| 710 m_isPresenting = false; | 741 m_isPresenting = false; |
| 711 OnPresentChange(); | 742 OnPresentChange(); |
| 712 m_fullscreenCheckTimer.stop(); | 743 m_fullscreenCheckTimer.stop(); |
| 713 if (m_display) | 744 if (m_display) |
| 714 m_display->ExitPresent(); | 745 m_display->ExitPresent(); |
| 715 return; | 746 return; |
| 716 } | 747 } |
| 717 m_reenteredFullscreen = true; | 748 m_reenteredFullscreen = true; |
| 718 auto canvas = m_layer.source(); | 749 auto canvas = m_layer.source().getAsHTMLCanvasElement(); |
| 719 Document* doc = this->document(); | 750 Document* doc = this->document(); |
| 720 std::unique_ptr<UserGestureIndicator> gestureIndicator; | 751 std::unique_ptr<UserGestureIndicator> gestureIndicator; |
| 721 if (doc) { | 752 if (doc) { |
| 722 gestureIndicator = WTF::wrapUnique( | 753 gestureIndicator = WTF::wrapUnique( |
| 723 new UserGestureIndicator(DocumentUserGestureToken::create( | 754 new UserGestureIndicator(DocumentUserGestureToken::create( |
| 724 doc, UserGestureToken::Status::PossiblyExistingGesture))); | 755 doc, UserGestureToken::Status::PossiblyExistingGesture))); |
| 725 } | 756 } |
| 726 Fullscreen::requestFullscreen(*canvas); | 757 Fullscreen::requestFullscreen(*canvas); |
| 727 } | 758 } |
| 728 } | 759 } |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 773 visitor->trace(m_stageParameters); | 804 visitor->trace(m_stageParameters); |
| 774 visitor->trace(m_eyeParametersLeft); | 805 visitor->trace(m_eyeParametersLeft); |
| 775 visitor->trace(m_eyeParametersRight); | 806 visitor->trace(m_eyeParametersRight); |
| 776 visitor->trace(m_layer); | 807 visitor->trace(m_layer); |
| 777 visitor->trace(m_renderingContext); | 808 visitor->trace(m_renderingContext); |
| 778 visitor->trace(m_scriptedAnimationController); | 809 visitor->trace(m_scriptedAnimationController); |
| 779 visitor->trace(m_pendingPresentResolvers); | 810 visitor->trace(m_pendingPresentResolvers); |
| 780 } | 811 } |
| 781 | 812 |
| 782 } // namespace blink | 813 } // namespace blink |
| OLD | NEW |