blob: 36832fb82a7079c50bb3323d078cd671889ce736 [file] [log] [blame]
/*
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2001 Dirk Mueller (mueller@kde.org)
* (C) 2006 Alexey Proskuryakov (ap@webkit.org)
* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2011 Apple Inc. All rights
* reserved.
* Copyright (C) 2008 Torch Mobile Inc. All rights reserved.
* (http://www.torchmobile.com/)
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "third_party/blink/renderer/core/page/viewport_description.h"
#include "build/build_config.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.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/page/page.h"
#include "third_party/blink/renderer/platform/histogram.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
namespace blink {
static const float& CompareIgnoringAuto(const float& value1,
const float& value2,
const float& (*compare)(const float&,
const float&)) {
if (value1 == ViewportDescription::kValueAuto)
return value2;
if (value2 == ViewportDescription::kValueAuto)
return value1;
return compare(value1, value2);
}
float ViewportDescription::ResolveViewportLength(
const Length& length,
const FloatSize& initial_viewport_size,
Direction direction) {
if (length.IsAuto())
return ViewportDescription::kValueAuto;
if (length.IsFixed())
return length.GetFloatValue();
if (length.GetType() == kExtendToZoom)
return ViewportDescription::kValueExtendToZoom;
if (length.IsPercent() && direction == kHorizontal)
return initial_viewport_size.Width() * length.GetFloatValue() / 100.0f;
if (length.IsPercent() && direction == kVertical)
return initial_viewport_size.Height() * length.GetFloatValue() / 100.0f;
if (length.GetType() == kDeviceWidth)
return initial_viewport_size.Width();
if (length.GetType() == kDeviceHeight)
return initial_viewport_size.Height();
NOTREACHED();
return ViewportDescription::kValueAuto;
}
PageScaleConstraints ViewportDescription::Resolve(
const FloatSize& initial_viewport_size,
const Length& legacy_fallback_width) const {
float result_width = kValueAuto;
Length copy_max_width = max_width;
Length copy_min_width = min_width;
// In case the width (used for min- and max-width) is undefined.
if (IsLegacyViewportType() && max_width.IsAuto()) {
// The width viewport META property is translated into 'width' descriptors,
// setting the 'min' value to 'extend-to-zoom' and the 'max' value to the
// intended length. In case the UA-defines a min-width, use that as length.
if (zoom == ViewportDescription::kValueAuto) {
copy_min_width = Length(kExtendToZoom);
copy_max_width = legacy_fallback_width;
} else if (max_height.IsAuto()) {
copy_min_width = Length(kExtendToZoom);
copy_max_width = Length(kExtendToZoom);
}
}
float result_max_width =
ResolveViewportLength(copy_max_width, initial_viewport_size, kHorizontal);
float result_min_width =
ResolveViewportLength(copy_min_width, initial_viewport_size, kHorizontal);
float result_height = kValueAuto;
float result_max_height =
ResolveViewportLength(max_height, initial_viewport_size, kVertical);
float result_min_height =
ResolveViewportLength(min_height, initial_viewport_size, kVertical);
float result_zoom = zoom;
float result_min_zoom = min_zoom;
float result_max_zoom = max_zoom;
bool result_user_zoom = user_zoom;
// Resolve min-zoom and max-zoom values.
if (result_min_zoom != ViewportDescription::kValueAuto &&
result_max_zoom != ViewportDescription::kValueAuto)
result_max_zoom = std::max(result_min_zoom, result_max_zoom);
// Constrain zoom value to the [min-zoom, max-zoom] range.
if (result_zoom != ViewportDescription::kValueAuto)
result_zoom = CompareIgnoringAuto(
result_min_zoom,
CompareIgnoringAuto(result_max_zoom, result_zoom, std::min), std::max);
float extend_zoom =
CompareIgnoringAuto(result_zoom, result_max_zoom, std::min);
// Resolve non-"auto" lengths to pixel lengths.
if (extend_zoom == ViewportDescription::kValueAuto) {
if (result_max_width == ViewportDescription::kValueExtendToZoom)
result_max_width = ViewportDescription::kValueAuto;
if (result_max_height == ViewportDescription::kValueExtendToZoom)
result_max_height = ViewportDescription::kValueAuto;
if (result_min_width == ViewportDescription::kValueExtendToZoom)
result_min_width = result_max_width;
if (result_min_height == ViewportDescription::kValueExtendToZoom)
result_min_height = result_max_height;
} else {
float extend_width = initial_viewport_size.Width() / extend_zoom;
float extend_height = initial_viewport_size.Height() / extend_zoom;
if (result_max_width == ViewportDescription::kValueExtendToZoom)
result_max_width = extend_width;
if (result_max_height == ViewportDescription::kValueExtendToZoom)
result_max_height = extend_height;
if (result_min_width == ViewportDescription::kValueExtendToZoom)
result_min_width =
CompareIgnoringAuto(extend_width, result_max_width, std::max);
if (result_min_height == ViewportDescription::kValueExtendToZoom)
result_min_height =
CompareIgnoringAuto(extend_height, result_max_height, std::max);
}
// Resolve initial width from min/max descriptors.
if (result_min_width != ViewportDescription::kValueAuto ||
result_max_width != ViewportDescription::kValueAuto)
result_width = CompareIgnoringAuto(
result_min_width,
CompareIgnoringAuto(result_max_width, initial_viewport_size.Width(),
std::min),
std::max);
// Resolve initial height from min/max descriptors.
if (result_min_height != ViewportDescription::kValueAuto ||
result_max_height != ViewportDescription::kValueAuto)
result_height = CompareIgnoringAuto(
result_min_height,
CompareIgnoringAuto(result_max_height, initial_viewport_size.Height(),
std::min),
std::max);
// Resolve width value.
if (result_width == ViewportDescription::kValueAuto) {
if (result_height == ViewportDescription::kValueAuto ||
!initial_viewport_size.Height())
result_width = initial_viewport_size.Width();
else
result_width = result_height * (initial_viewport_size.Width() /
initial_viewport_size.Height());
}
// Resolve height value.
if (result_height == ViewportDescription::kValueAuto) {
if (!initial_viewport_size.Width())
result_height = initial_viewport_size.Height();
else
result_height = result_width * initial_viewport_size.Height() /
initial_viewport_size.Width();
}
// Resolve initial-scale value.
if (result_zoom == ViewportDescription::kValueAuto) {
if (result_width != ViewportDescription::kValueAuto && result_width > 0)
result_zoom = initial_viewport_size.Width() / result_width;
if (result_height != ViewportDescription::kValueAuto && result_height > 0) {
// if 'auto', the initial-scale will be negative here and thus ignored.
result_zoom = std::max<float>(
result_zoom, initial_viewport_size.Height() / result_height);
}
// Reconstrain zoom value to the [min-zoom, max-zoom] range.
result_zoom = CompareIgnoringAuto(
result_min_zoom,
CompareIgnoringAuto(result_max_zoom, result_zoom, std::min), std::max);
}
// If user-scalable = no, lock the min/max scale to the computed initial
// scale.
if (!result_user_zoom)
result_min_zoom = result_max_zoom = result_zoom;
// Only set initialScale to a value if it was explicitly set.
if (zoom == ViewportDescription::kValueAuto)
result_zoom = ViewportDescription::kValueAuto;
PageScaleConstraints result;
result.minimum_scale = result_min_zoom;
result.maximum_scale = result_max_zoom;
result.initial_scale = result_zoom;
result.layout_size.SetWidth(result_width);
result.layout_size.SetHeight(result_height);
return result;
}
void ViewportDescription::ReportMobilePageStats(
const LocalFrame* main_frame) const {
if (!main_frame || !main_frame->GetPage() || !main_frame->View() ||
!main_frame->GetDocument())
return;
if (!main_frame->GetSettings() ||
!main_frame->GetSettings()->GetViewportEnabled())
return;
// Avoid chrome:// pages like the new-tab page (on Android new tab is
// non-http).
if (!main_frame->GetDocument()->Url().ProtocolIsInHTTPFamily())
return;
DEFINE_STATIC_LOCAL(
EnumerationHistogram, meta_tag_type_histogram,
("Viewport.MetaTagType", static_cast<int>(ViewportUMAType::kTypeCount)));
if (!IsSpecifiedByAuthor()) {
meta_tag_type_histogram.Count(
main_frame->GetDocument()->IsMobileDocument()
? static_cast<int>(ViewportUMAType::kXhtmlMobileProfile)
: static_cast<int>(ViewportUMAType::kNoViewportTag));
return;
}
if (IsMetaViewportType()) {
if (max_width.IsFixed()) {
meta_tag_type_histogram.Count(
static_cast<int>(ViewportUMAType::kConstantWidth));
if (main_frame->View()) {
// To get an idea of how "far" the viewport is from the device's ideal
// width, we report the zoom level that we'd need to be at for the
// entire page to be visible.
int viewport_width = max_width.IntValue();
int window_width =
main_frame->GetPage()->GetVisualViewport().Size().Width();
int overview_zoom_percent =
100 * window_width / static_cast<float>(viewport_width);
DEFINE_STATIC_LOCAL(SparseHistogram, overview_zoom_histogram,
("Viewport.OverviewZoom"));
overview_zoom_histogram.Sample(overview_zoom_percent);
}
} else if (max_width.GetType() == blink::kDeviceWidth ||
max_width.GetType() == blink::kExtendToZoom) {
meta_tag_type_histogram.Count(
static_cast<int>(ViewportUMAType::kDeviceWidth));
} else {
// Overflow bucket for cases we may be unaware of.
meta_tag_type_histogram.Count(
static_cast<int>(ViewportUMAType::kMetaWidthOther));
}
} else if (type == ViewportDescription::kHandheldFriendlyMeta) {
meta_tag_type_histogram.Count(
static_cast<int>(ViewportUMAType::kMetaHandheldFriendly));
} else if (type == ViewportDescription::kMobileOptimizedMeta) {
meta_tag_type_histogram.Count(
static_cast<int>(ViewportUMAType::kMetaMobileOptimized));
}
}
bool ViewportDescription::MatchesHeuristicsForGpuRasterization() const {
bool enable_viewport_restriction = base::FeatureList::IsEnabled(
features::kEnableGpuRasterizationViewportRestriction);
return !enable_viewport_restriction || IsSpecifiedByAuthor();
}
} // namespace blink