blob: d87726bb828c90ba248172894b2523451ba839c1 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/frame/viewport_data.h"
#include "third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom-blink.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
#include "third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/viewport_description.h"
#include "ui/base/ime/mojom/virtual_keyboard_types.mojom-blink.h"
namespace blink {
ViewportData::ViewportData(Document& document)
: document_(document),
display_cutout_host_(document_->GetExecutionContext()) {}
void ViewportData::Trace(Visitor* visitor) const {
visitor->Trace(document_);
visitor->Trace(display_cutout_host_);
}
void ViewportData::Shutdown() {
display_cutout_host_.reset();
}
bool ViewportData::ShouldMergeWithLegacyDescription(
ViewportDescription::Type origin) const {
return document_->GetSettings() &&
document_->GetSettings()->GetViewportMetaMergeContentQuirk() &&
legacy_viewport_description_.IsMetaViewportType() &&
legacy_viewport_description_.type == origin;
}
void ViewportData::SetViewportDescription(
const ViewportDescription& viewport_description) {
if (viewport_description.IsLegacyViewportType()) {
if (viewport_description == legacy_viewport_description_)
return;
legacy_viewport_description_ = viewport_description;
} else {
if (viewport_description == viewport_description_)
return;
viewport_description_ = viewport_description;
// Store the UA specified width to be used as the default "fallback" width.
// i.e. the width to use if the author doesn't specify a layout width.
if (!viewport_description.IsSpecifiedByAuthor())
viewport_default_min_width_ = viewport_description.min_width;
}
UpdateViewportDescription();
}
ViewportDescription ViewportData::GetViewportDescription() const {
ViewportDescription applied_viewport_description = viewport_description_;
bool viewport_meta_enabled =
document_->GetSettings() &&
document_->GetSettings()->GetViewportMetaEnabled();
if (legacy_viewport_description_.type !=
ViewportDescription::kUserAgentStyleSheet &&
viewport_meta_enabled)
applied_viewport_description = legacy_viewport_description_;
if (ShouldOverrideLegacyDescription(viewport_description_.type))
applied_viewport_description = viewport_description_;
// Setting `navigator.virtualKeyboard.overlaysContent` should override the
// virtual-keyboard mode set from the viewport meta tag.
if (virtual_keyboard_overlays_content_) {
applied_viewport_description.virtual_keyboard_mode =
ui::mojom::blink::VirtualKeyboardMode::kOverlaysContent;
}
return applied_viewport_description;
}
void ViewportData::UpdateViewportDescription() {
if (!document_->GetFrame())
return;
// If the viewport_fit has changed we should send this to the browser. We
// use the legacy viewport description which contains the viewport_fit
// defined from the layout meta tag.
mojom::ViewportFit current_viewport_fit =
GetViewportDescription().GetViewportFit();
// If we are forcing to expand into the display cutout then we should override
// the viewport fit value.
if (force_expand_display_cutout_)
current_viewport_fit = mojom::ViewportFit::kCoverForcedByUserAgent;
if (viewport_fit_ != current_viewport_fit) {
if (AssociatedInterfaceProvider* provider =
document_->GetFrame()
->Client()
->GetRemoteNavigationAssociatedInterfaces()) {
// Bind the mojo interface.
if (!display_cutout_host_.is_bound()) {
provider->GetInterface(
display_cutout_host_.BindNewEndpointAndPassReceiver(
provider->GetTaskRunner()));
DCHECK(display_cutout_host_.is_bound());
}
// Even though we bind the mojo interface above there still may be cases
// where this will fail (e.g. unit tests).
display_cutout_host_->NotifyViewportFitChanged(current_viewport_fit);
// Track usage of any non-default viewport-fit.
if (document_->GetFrame()->IsOutermostMainFrame()) {
if (current_viewport_fit == mojom::blink::ViewportFit::kContain) {
UseCounter::Count(document_, WebFeature::kViewportFitContain);
} else if (current_viewport_fit == mojom::blink::ViewportFit::kCover ||
current_viewport_fit ==
mojom::blink::ViewportFit::kCoverForcedByUserAgent) {
UseCounter::Count(document_, WebFeature::kViewportFitCover);
// TODO(https://crbug.com/1482559) remove tracking this union of
// features after data collected (end of '23)
UseCounter::Count(document_,
WebFeature::kViewportFitCoverOrSafeAreaInsetBottom);
// TODO(https://crbug.com/1482559#c23) remove this line by end of
// 2023.
VLOG(0) << "E2E_Used ViewportFitCover";
}
}
}
viewport_fit_ = current_viewport_fit;
}
if (document_->GetFrame()->IsMainFrame() &&
document_->GetPage()->GetVisualViewport().IsActiveViewport()) {
document_->GetPage()->GetChromeClient().DispatchViewportPropertiesDidChange(
GetViewportDescription());
}
}
void ViewportData::SetExpandIntoDisplayCutout(bool expand) {
if (force_expand_display_cutout_ == expand)
return;
force_expand_display_cutout_ = expand;
UpdateViewportDescription();
}
void ViewportData::SetVirtualKeyboardOverlaysContent(bool overlays_content) {
if (virtual_keyboard_overlays_content_ == overlays_content)
return;
virtual_keyboard_overlays_content_ = overlays_content;
UpdateViewportDescription();
}
} // namespace blink