blob: 46125fd046c7b48ca5e52418d9310b976c62e32f [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// 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/html/anchor_element_metrics.h"
#include "base/metrics/histogram_macros.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/html/html_anchor_element.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/platform/histogram.h"
namespace blink {
IntSize AnchorElementMetrics::AccumulatedScrollOffset(
const HTMLAnchorElement& anchor_element) {
IntSize offset;
Frame* frame = anchor_element.GetDocument().GetFrame();
while (frame && frame->View() && frame->IsLocalFrame()) {
offset += ToLocalFrame(frame)->View()->LayoutViewport()->ScrollOffsetInt();
frame = frame->Tree().Parent();
}
return offset;
}
bool AnchorElementMetrics::IsInIFrame(const HTMLAnchorElement& anchor_element) {
Frame* frame = anchor_element.GetDocument().GetFrame();
while (frame && frame->IsLocalFrame()) {
HTMLFrameOwnerElement* owner =
ToLocalFrame(frame)->GetDocument()->LocalOwner();
if (owner && IsHTMLIFrameElement(owner))
return true;
frame = frame->Tree().Parent();
}
return false;
}
base::Optional<AnchorElementMetrics> AnchorElementMetrics::From(
const HTMLAnchorElement& anchor_element) {
LocalFrame* local_frame = anchor_element.GetDocument().GetFrame();
LayoutObject* layout_object = anchor_element.GetLayoutObject();
if (!local_frame || !layout_object)
return base::nullopt;
LocalFrameView* local_frame_view = local_frame->View();
LocalFrameView* root_frame_view = local_frame->LocalFrameRoot().View();
if (!local_frame_view || !root_frame_view)
return base::nullopt;
IntSize visible_size =
root_frame_view->LayoutViewport()->VisibleContentRect().Size();
if (visible_size.IsEmpty())
return base::nullopt;
IntRect target_rect = EnclosingIntRect(layout_object->AbsoluteVisualRect());
// Adjust target location due to root layer scrolling.
// Then map the target location to the root frame.
IntPoint target_location(target_rect.Location());
target_location.Move(-local_frame_view->LayoutViewport()->ScrollOffsetInt());
target_location = local_frame_view->ConvertToRootFrame(target_location);
// Calculate features of the anchor element.
float ratio_area = FloatSize(target_rect.Size()).Area() / visible_size.Area();
float ratio_distance_root_top =
float(target_location.Y() +
AccumulatedScrollOffset(anchor_element).Height()) /
visible_size.Height();
float ratio_distance_visible_top =
float(target_location.Y()) / visible_size.Height();
return AnchorElementMetrics(ratio_area, ratio_distance_root_top,
ratio_distance_visible_top,
IsInIFrame(anchor_element));
}
void AnchorElementMetrics::RecordMetrics() const {
UMA_HISTOGRAM_PERCENTAGE("AnchorElementMetrics.Clicked.RatioArea",
int(ratio_area * 100));
UMA_HISTOGRAM_COUNTS_10000(
"AnchorElementMetrics.Clicked.RatioDistanceRootTop",
int(ratio_distance_root_top * 100));
UMA_HISTOGRAM_PERCENTAGE(
"AnchorElementMetrics.Clicked.RatioDistanceVisibleTop",
int(ratio_distance_visible_top * 100));
UMA_HISTOGRAM_BOOLEAN("AnchorElementMetrics.Clicked.IsInIFrame",
is_in_iframe);
}
} // namespace blink