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 |