Skip to content

Commit

Permalink
Syncing content from committish f48678bcc836e2f37bf1d8fe6a9736d729750365
Browse files Browse the repository at this point in the history
  • Loading branch information
reunion-maestro-bot committed Jul 9, 2024
1 parent 98a60c8 commit fd8e26f
Show file tree
Hide file tree
Showing 9 changed files with 240 additions and 84 deletions.
129 changes: 100 additions & 29 deletions controls/dev/WebView2/WebView2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#include "Windows.Globalization.h"
#include <wrl\event.h>
#include "MuxcTraceLogging.h"
#include <FrameworkUdk/Containment.h>

// Bug 51787766: [1.5 Servicing] [GitHub #2330][Acc][PowerBI][UWP MSAA][Amazon Prime] Initial focus not set to WebView2 when WV2 is the only control
#define WINAPPSDK_CHANGEID_51787766 51787766

using namespace Microsoft::WRL;

Expand Down Expand Up @@ -563,44 +567,91 @@ void WebView2::RegisterCoreEventHandlers()
if (moveFocusRequestedReason == winrt::CoreWebView2MoveFocusReason::Next ||
moveFocusRequestedReason == winrt::CoreWebView2MoveFocusReason::Previous)
{
winrt::FocusNavigationDirection xamlDirection{ moveFocusRequestedReason == winrt::CoreWebView2MoveFocusReason::Next ?
winrt::FocusNavigationDirection::Next : winrt::FocusNavigationDirection::Previous };
winrt::FindNextElementOptions findNextElementOptions;
winrt::XamlRoot xamlRoot = strongThis->XamlRoot();
if (xamlRoot)
{
winrt::FocusNavigationDirection xamlDirection = moveFocusRequestedReason == winrt::CoreWebView2MoveFocusReason::Next
? winrt::FocusNavigationDirection::Next
: winrt::FocusNavigationDirection::Previous;

winrt::FindNextElementOptions findNextElementOptions;
findNextElementOptions.SearchRoot(xamlRoot.Content());

winrt::DependencyObject nextElement = winrt::FocusManager::FindNextElement(xamlDirection, findNextElementOptions);
if (nextElement)

if (WinAppSdk::Containment::IsChangeEnabled<WINAPPSDK_CHANGEID_51787766>())
{
// TODO_WebView2: We should check TryMoveFocusAsync() result before returning since FindNextElement()
// only finds the next focusable element, but does not guarantee that we can
// actually focus on it (eg it could be empty/in the process of loading).
// Waiting on this result via winrt/cpp coroutine results in the WINRT_ASSERT
// warning about a blocking wait on UI Thread.
//
// We will address this scenario properly as part of:
// Task 23157748: WebView2 should implement IInternalCoreWindowFocus (use Xaml's unified focus model)
//
// For now, we'll assign the return value of TryMoveFocusAsync() to a dummy variable
// in order to avoid the code analysis error C26444:
//
// https://docs.microsoft.com/en-us/cpp/code-quality/c26444?view=vs-2019

// If core webview is also losing focus via something other than TAB (web LostFocus event fired)
// and the TAB handling is arriving later (eg due to longer MOJO delay), skip manually moving Xaml Focus to next element.
auto focusedElement = winrt::FocusManager::GetFocusedElement(xamlRoot).try_as<winrt::UIElement>();
auto thisElement = strongThis->try_as<winrt::UIElement>();
if (thisElement == focusedElement)
winrt::DependencyObject focusedElement = winrt::FocusManager::GetFocusedElement(xamlRoot).try_as<winrt::DependencyObject>();
if (nextElement && nextElement != focusedElement)
{
// TODO_WebView2: We should check TryMoveFocusAsync() result before returning since FindNextElement()
// only finds the next focusable element, but does not guarantee that we can
// actually focus on it (eg it could be empty/in the process of loading).
// Waiting on this result via winrt/cpp coroutine results in the WINRT_ASSERT
// warning about a blocking wait on UI Thread.
//
// We will address this scenario properly as part of:
// Task 23157748: WebView2 should implement IInternalCoreWindowFocus (use Xaml's unified focus model)
//
// For now, we'll assign the return value of TryMoveFocusAsync() to a dummy variable
// in order to avoid the code analysis error C26444:
//
// https://docs.microsoft.com/en-us/cpp/code-quality/c26444?view=vs-2019

// If core webview is also losing focus via something other than TAB (web LostFocus event fired)
// and the TAB handling is arriving later (eg due to longer MOJO delay), skip manually moving Xaml Focus to next element.
winrt::DependencyObject thisElement = strongThis->try_as<winrt::DependencyObject>();
if (thisElement == focusedElement)
{
// Move focus to the next XAML element
const auto _ = winrt::FocusManager::TryMoveFocusAsync(xamlDirection, findNextElementOptions);
}
}
else
{
const auto _ = winrt::FocusManager::TryMoveFocusAsync(xamlDirection, findNextElementOptions);
// Handle the case where there is no "next" focusable XAML element (WebView2 is first/last/only element),
// which we are in if FindNextElement() returns either null or the (already focused) WebView2. The appropriate
// behavior here is to cycle focus inside the webview, "wrapping around" to the other end (regardless of
// WebView2.KeyboardNavigationMode).To achieve this, manually Call MoveFocus() in the specified direction.
strongThis->MoveFocusIntoCoreWebView2(moveFocusRequestedReason);
}

// Always mark the args handled to prevent CoreWebView2Controller's "default behavior" which breaks XAML focus expectations (by explicitly changing HWND focus)
// More info: https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2movefocusrequestedeventargs?view=webview2-winrt-1.0.2535.41#handled
args.Handled(TRUE);
}
else
{
if (nextElement)
{
// TODO_WebView2: We should check TryMoveFocusAsync() result before returning since FindNextElement()
// only finds the next focusable element, but does not guarantee that we can
// actually focus on it (eg it could be empty/in the process of loading).
// Waiting on this result via winrt/cpp coroutine results in the WINRT_ASSERT
// warning about a blocking wait on UI Thread.
//
// We will address this scenario properly as part of:
// Task 23157748: WebView2 should implement IInternalCoreWindowFocus (use Xaml's unified focus model)
//
// For now, we'll assign the return value of TryMoveFocusAsync() to a dummy variable
// in order to avoid the code analysis error C26444:
//
// https://docs.microsoft.com/en-us/cpp/code-quality/c26444?view=vs-2019

// If core webview is also losing focus via something other than TAB (web LostFocus event fired)
// and the TAB handling is arriving later (eg due to longer MOJO delay), skip manually moving Xaml Focus to next element.
auto focusedElement = winrt::FocusManager::GetFocusedElement(xamlRoot).try_as<winrt::UIElement>();
auto thisElement = strongThis->try_as<winrt::UIElement>();
if (thisElement == focusedElement)
{
const auto _ = winrt::FocusManager::TryMoveFocusAsync(xamlDirection, findNextElementOptions);
}

args.Handled(TRUE);
}
// If nextElement is null, focus is maintained in Anaheim by not marking Handled.
}
}

// If nextElement is null, focus is maintained in Anaheim by not marking Handled.
}
}
} });
Expand Down Expand Up @@ -1246,15 +1297,35 @@ void WebView2::FireCoreWebView2Initialized(winrt::hresult exception)
m_coreWebView2InitializedEventSource(*this, *eventArgs);
}

void WebView2::HandleGotFocus(const winrt::Windows::Foundation::IInspectable&, const winrt::RoutedEventArgs&) noexcept
void WebView2::MoveFocusIntoCoreWebView2(winrt::CoreWebView2MoveFocusReason reason)
{
if (m_coreWebView && m_xamlFocusChangeInfo.m_isPending)
if (m_coreWebView && m_coreWebViewController)
{
CoreWebView2RunIgnoreInvalidStateSync(
[&]()
{
m_coreWebViewController.MoveFocus(m_xamlFocusChangeInfo.m_storedMoveFocusReason);
m_coreWebViewController.MoveFocus(reason);
});
}
}

void WebView2::HandleGotFocus(const winrt::Windows::Foundation::IInspectable&, const winrt::RoutedEventArgs&) noexcept
{
if (m_coreWebView && m_xamlFocusChangeInfo.m_isPending)
{
if (WinAppSdk::Containment::IsChangeEnabled<WINAPPSDK_CHANGEID_51787766>())
{
MoveFocusIntoCoreWebView2(m_xamlFocusChangeInfo.m_storedMoveFocusReason);
}
else
{
CoreWebView2RunIgnoreInvalidStateSync(
[&]()
{
m_coreWebViewController.MoveFocus(m_xamlFocusChangeInfo.m_storedMoveFocusReason);
});
}

m_xamlFocusChangeInfo.m_isPending = false;
}
}
Expand Down
2 changes: 1 addition & 1 deletion controls/dev/WebView2/WebView2.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class WebView2 :
void UpdateSourceInternal();
void FireCoreProcessFailedEvent(const winrt::CoreWebView2ProcessFailedEventArgs& args);
void FireCoreWebView2Initialized(winrt::hresult exception);

void MoveFocusIntoCoreWebView2(winrt::CoreWebView2MoveFocusReason reason);
void UpdateDefaultVisualBackgroundColor();

HWND GetHostHwnd() noexcept;
Expand Down
41 changes: 28 additions & 13 deletions dxaml/xcp/components/imaging/ImageCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
#include <MUX-ETWEvents.h>
#include <palnetwork.h>
#include <PalResourceManager.h>
#include <FrameworkUdk/Containment.h>

// Telemetry: Image Decoding Activity is skipped in WinAppSDK 1.5.5+ Servicing releases to avoid crashing
// Bug 44612834: [1.5 servicing] [Watson Failure] caused by FAIL_FAST_FATAL_APP_EXIT_c0000409_Microsoft.UI.Xaml.dll!ImagingTelemetry::ImageDecodeActivity::Split
#define WINAPPSDK_CHANGEID_44612834 44612834

typedef ImageAsyncCallback<ImageCache> ImageCacheAsyncTask;

Expand Down Expand Up @@ -341,17 +346,20 @@ _Check_return_ HRESULT ImageCache::TriggerProcessDecodeRequests()
{
if (!m_hasProcessDecodeRequestsTask)
{
// This ImageCache may be associated with multiple ImageSources (i.e. the same image decoding to multiple
// different sizes). Telemetry is associated with the decoded image, so report telemetry for all the
// decodes that will be triggered by this ImageCache.
for (ImageDecodeRequest* decodeRequest : m_decodeRequests)
if (!WinAppSdk::Containment::IsChangeEnabled<WINAPPSDK_CHANGEID_44612834>())
{
const auto& decodeParams = decodeRequest->GetDecodeParams();
// This ImageCache may be associated with multiple ImageSources (i.e. the same image decoding to multiple
// different sizes). Telemetry is associated with the decoded image, so report telemetry for all the
// decodes that will be triggered by this ImageCache.
for (ImageDecodeRequest* decodeRequest : m_decodeRequests)
{
const auto& decodeParams = decodeRequest->GetDecodeParams();

// The call below won't actually AV if there's nothing logging an ETW trace. Assert it explicitly so we
// crash consistently if it's null.
ASSERT(decodeParams->GetDecodeActivity());
decodeParams->GetDecodeActivity()->QueueProcessDecodeRequests(decodeParams->GetImageId(), decodeParams->GetStrSource().GetBuffer());
// The call below won't actually AV if there's nothing logging an ETW trace. Assert it explicitly so we
// crash consistently if it's null.
ASSERT(decodeParams->GetDecodeActivity());
decodeParams->GetDecodeActivity()->QueueProcessDecodeRequests(decodeParams->GetImageId(), decodeParams->GetStrSource().GetBuffer());
}
}

auto task = make_xref<ImageCacheAsyncTask>(this, &ImageCache::ProcessDecodeRequests);
Expand All @@ -372,10 +380,13 @@ _Check_return_ HRESULT ImageCache::ProcessDecodeRequests()
{
m_hasProcessDecodeRequestsTask = FALSE;

for (ImageDecodeRequest* decodeRequest : m_decodeRequests)
if (!WinAppSdk::Containment::IsChangeEnabled<WINAPPSDK_CHANGEID_44612834>())
{
const auto& decodeParams = decodeRequest->GetDecodeParams();
decodeParams->GetDecodeActivity()->ProcessDecodeRequests(decodeParams->GetImageId(), decodeParams->GetStrSource().GetBuffer(), m_State);
for (ImageDecodeRequest* decodeRequest : m_decodeRequests)
{
const auto& decodeParams = decodeRequest->GetDecodeParams();
decodeParams->GetDecodeActivity()->ProcessDecodeRequests(decodeParams->GetImageId(), decodeParams->GetStrSource().GetBuffer(), m_State);
}
}

//
Expand Down Expand Up @@ -487,7 +498,11 @@ _Check_return_ HRESULT ImageCache::BeginDecode(
const auto& decodeParams = decodeRequest->GetDecodeParams();
const std::shared_ptr<ImagingTelemetry::ImageDecodeActivity>& decodeActivity = decodeParams->GetDecodeActivity();

decodeActivity->QueueDecodeFromImageCache(decodeParams->GetImageId(), decodeParams->GetStrSource().GetBuffer());
if (decodeActivity)
{
decodeActivity->QueueDecodeFromImageCache(decodeParams->GetImageId(), decodeParams->GetStrSource().GetBuffer());
}

auto parseHR = m_encodedImageData->Parse(m_core->GetGraphicsDevice(), m_core->GetContentRootMaxSize());

if (FAILED(parseHR))
Expand Down
14 changes: 13 additions & 1 deletion dxaml/xcp/components/imaging/ImageProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
#include "ImageProvider.h"
#include "ImageDecodeRequest.h"
#include "ImageDecodeParams.h"
#include <FrameworkUdk/Containment.h>

// Telemetry: Image Decoding Activity is skipped in WinAppSDK 1.5.5+ Servicing releases to avoid crashing
// Bug 44612834: [1.5 servicing] [Watson Failure] caused by FAIL_FAST_FATAL_APP_EXIT_c0000409_Microsoft.UI.Xaml.dll!ImagingTelemetry::ImageDecodeActivity::Split
#define WINAPPSDK_CHANGEID_44612834 44612834

_Check_return_ HRESULT
ImageProvider::CopyImage(
Expand All @@ -37,12 +42,19 @@ ImageProvider::CopyImage(

std::shared_ptr<ImagingTelemetry::ImageDecodeActivity>& ImageProvider::GetDecodeActivity()
{
EnsureDecodeActivity();
if (!WinAppSdk::Containment::IsChangeEnabled<WINAPPSDK_CHANGEID_44612834>())
{
EnsureDecodeActivity();
}

return m_decodeActivity;
}

void ImageProvider::EnsureDecodeActivity()
{
// Telemetry: Image Decoding Activity is skipped in WinAppSDK 1.5.5+ Servicing releases to avoid crashing bug 44612834.
ASSERT(!WinAppSdk::Containment::IsChangeEnabled<WINAPPSDK_CHANGEID_44612834>());

if (!m_decodeActivity)
{
m_decodeActivity = std::make_shared<ImagingTelemetry::ImageDecodeActivity>(ImagingTelemetry::ImageDecodeActivity::Start());
Expand Down
10 changes: 8 additions & 2 deletions dxaml/xcp/components/imaging/SoftwareBitmapSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,10 @@ CSoftwareBitmapSource::SetBitmap(
{
ASSERT(m_spAbortableImageOperation == nullptr);

GetContext()->GetImageProvider()->GetDecodeActivity()->SetSoftwareBitmap(reinterpret_cast<uint64_t>(this));
if (const auto& decodeActivity = GetContext()->GetImageProvider()->GetDecodeActivity())
{
decodeActivity->SetSoftwareBitmap(reinterpret_cast<uint64_t>(this));
}

IFC_RETURN(ReloadSource(false /* forceCopyToSoftwareSurface */));
}
Expand Down Expand Up @@ -178,7 +181,10 @@ _Check_return_ HRESULT CSoftwareBitmapSource::OnSoftwareBitmapImageAvailable(_In

attemptCopyToSoftwareSurfaceInstead = true;

GetContext()->GetImageProvider()->GetDecodeActivity()->SoftwareBitmapFallbackAfterUploadError(reinterpret_cast<uint64_t>(this), uploadHResult);
if (const auto& decodeActivity = GetContext()->GetImageProvider()->GetDecodeActivity())
{
decodeActivity->SoftwareBitmapFallbackAfterUploadError(reinterpret_cast<uint64_t>(this), uploadHResult);
}

// Force a copy into a software surface, which will never hit a device lost error. We'll upload this into a
// hardware surface later on a UI thread frame.
Expand Down
Loading

0 comments on commit fd8e26f

Please sign in to comment.