Commit ec7bcab8 authored by Dylan Cutler's avatar Dylan Cutler Committed by Commit Bot

Instrument document.scrollingElement.client[Width|Height] for

identifiability study.

This API can be used to compute the size of a client's scrollbar, which
is information which could be used to build a fingerprint to track users
across different origins.

This CL refactors the method used for instrumenting
HTMLElement.offset[Width|Height] introduced in
http://crrev.com/c/2436650 to support both use cases.

Bug: 973801
Change-Id: I518841aad9093b8df9368f2e6977ebab20536a37
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2472528Reviewed-by: default avatarAsanka Herath <asanka@chromium.org>
Reviewed-by: default avatarDavid Bokan <bokan@chromium.org>
Commit-Queue: Dylan Cutler <dylancutler@google.com>
Cr-Commit-Position: refs/heads/master@{#818323}
parent 5f7b8b75
...@@ -229,8 +229,8 @@ class IdentifiableSurface { ...@@ -229,8 +229,8 @@ class IdentifiableSurface {
}; };
enum class ScrollbarSurface : uint64_t { enum class ScrollbarSurface : uint64_t {
kBodyOffsetWidth = 0, kScrollingElementWidth = 0,
kBodyOffsetHeight = 1, kScrollingElementHeight = 1,
kElemScrollbarWidth = 2, kElemScrollbarWidth = 2,
kElemScrollbarHeight = 3, kElemScrollbarHeight = 3,
}; };
......
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include <utility> #include <utility>
#include "cc/input/snap_selection_strategy.h" #include "cc/input/snap_selection_strategy.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
#include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink.h" #include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/dictionary.h" #include "third_party/blink/renderer/bindings/core/v8/dictionary.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
...@@ -1273,6 +1275,70 @@ int Element::clientTop() { ...@@ -1273,6 +1275,70 @@ int Element::clientTop() {
return 0; return 0;
} }
void Element::RecordScrollbarSizeForStudy(int measurement,
bool is_width,
bool is_offset) {
if (!IdentifiabilityStudySettings::Get()->IsTypeAllowed(
IdentifiableSurface::Type::kScrollbarSize))
return;
// Check for presence of a scrollbar.
PaintLayerScrollableArea* area;
if (this == GetDocument().ScrollingElementNoLayout()) {
auto* view = GetDocument().View();
if (!view)
return;
area = view->LayoutViewport();
} else {
auto* layout = GetLayoutBox();
if (!layout)
return;
area = layout->GetScrollableArea();
}
if (!area || area->HasOverlayOverflowControls())
return;
Scrollbar* scrollbar =
is_width ? area->VerticalScrollbar() : area->HorizontalScrollbar();
// We intentionally exclude platform overlay scrollbars since their size
// cannot be detected in JavaScript using the methods below.
if (!scrollbar)
return;
IdentifiableSurface::ScrollbarSurface surface;
int scrollbar_size;
// There are two common ways to detect the size of a scrollbar in a DOM
// window. They are:
// 1. Compute the difference of the window.inner[Width|Height] and the
// corresponding document.scrollingElement.offset[Width|Height].
// 2. Any HTML element that insets the layout to fit a scrollbar, so it is
// measurable by a JavaScript program on a site.
if (this == GetDocument().scrollingElement()) {
LocalDOMWindow* dom_window = GetDocument().domWindow();
scrollbar_size =
(is_width ? dom_window->innerWidth() : dom_window->innerHeight()) -
measurement;
surface =
is_width
? IdentifiableSurface::ScrollbarSurface::kScrollingElementWidth
: IdentifiableSurface::ScrollbarSurface::kScrollingElementHeight;
} else if (is_offset) {
scrollbar_size = measurement - (is_width ? clientWidth() : clientHeight());
surface = is_width
? IdentifiableSurface::ScrollbarSurface::kElemScrollbarWidth
: IdentifiableSurface::ScrollbarSurface::kElemScrollbarHeight;
} else {
return;
}
blink::IdentifiabilityMetricBuilder(GetDocument().UkmSourceID())
.Set(blink::IdentifiableSurface::FromTypeAndToken(
blink::IdentifiableSurface::Type::kScrollbarSize, surface),
scrollbar_size)
.Record(GetDocument().UkmRecorder());
}
int Element::clientWidth() { int Element::clientWidth() {
// When in strict mode, clientWidth for the document element should return the // When in strict mode, clientWidth for the document element should return the
// width of the containing frame. // width of the containing frame.
...@@ -1293,29 +1359,40 @@ int Element::clientWidth() { ...@@ -1293,29 +1359,40 @@ int Element::clientWidth() {
// OverflowClipRect() may return infinite along a particular axis if // OverflowClipRect() may return infinite along a particular axis if
// |layout_view| is not a scroll-container. // |layout_view| is not a scroll-container.
DCHECK(layout_view->IsScrollContainer()); DCHECK(layout_view->IsScrollContainer());
return AdjustForAbsoluteZoom::AdjustLayoutUnit( int result =
layout_view->OverflowClipRect(PhysicalOffset()).Width(), AdjustForAbsoluteZoom::AdjustLayoutUnit(
layout_view->StyleRef()) layout_view->OverflowClipRect(PhysicalOffset()).Width(),
.Round(); layout_view->StyleRef())
.Round();
RecordScrollbarSizeForStudy(result, /* is_width= */ true,
/* is_offset= */ false);
return result;
} }
return AdjustForAbsoluteZoom::AdjustLayoutUnit( int result = AdjustForAbsoluteZoom::AdjustLayoutUnit(
LayoutUnit(layout_view->GetLayoutSize().Width()), LayoutUnit(layout_view->GetLayoutSize().Width()),
layout_view->StyleRef()) layout_view->StyleRef())
.Round(); .Round();
RecordScrollbarSizeForStudy(result, /* is_width= */ true,
/* is_offset= */ false);
return result;
} }
} }
GetDocument().UpdateStyleAndLayoutForNode(this, GetDocument().UpdateStyleAndLayoutForNode(this,
DocumentUpdateReason::kJavaScript); DocumentUpdateReason::kJavaScript);
if (LayoutBox* layout_object = GetLayoutBox()) int result = 0;
return AdjustForAbsoluteZoom::AdjustLayoutUnit( if (LayoutBox* layout_object = GetLayoutBox()) {
LayoutUnit( result =
layout_object AdjustForAbsoluteZoom::AdjustLayoutUnit(
->PixelSnappedClientWidthWithTableSpecialBehavior()), LayoutUnit(layout_object
layout_object->StyleRef()) ->PixelSnappedClientWidthWithTableSpecialBehavior()),
.Round(); layout_object->StyleRef())
return 0; .Round();
RecordScrollbarSizeForStudy(result, /* is_width= */ true,
/* is_offset= */ false);
}
return result;
} }
int Element::clientHeight() { int Element::clientHeight() {
...@@ -1339,29 +1416,40 @@ int Element::clientHeight() { ...@@ -1339,29 +1416,40 @@ int Element::clientHeight() {
// OverflowClipRect() may return infinite along a particular axis if // OverflowClipRect() may return infinite along a particular axis if
// |layout_view| is not a scroll-container. // |layout_view| is not a scroll-container.
DCHECK(layout_view->IsScrollContainer()); DCHECK(layout_view->IsScrollContainer());
return AdjustForAbsoluteZoom::AdjustLayoutUnit( int result =
layout_view->OverflowClipRect(PhysicalOffset()).Height(), AdjustForAbsoluteZoom::AdjustLayoutUnit(
layout_view->StyleRef()) layout_view->OverflowClipRect(PhysicalOffset()).Height(),
.Round(); layout_view->StyleRef())
.Round();
RecordScrollbarSizeForStudy(result, /* is_width= */ false,
/* is_offset= */ false);
return result;
} }
return AdjustForAbsoluteZoom::AdjustLayoutUnit( int result = AdjustForAbsoluteZoom::AdjustLayoutUnit(
LayoutUnit(layout_view->GetLayoutSize().Height()), LayoutUnit(layout_view->GetLayoutSize().Height()),
layout_view->StyleRef()) layout_view->StyleRef())
.Round(); .Round();
RecordScrollbarSizeForStudy(result, /* is_width= */ false,
/* is_offset= */ false);
return result;
} }
} }
GetDocument().UpdateStyleAndLayoutForNode(this, GetDocument().UpdateStyleAndLayoutForNode(this,
DocumentUpdateReason::kJavaScript); DocumentUpdateReason::kJavaScript);
if (LayoutBox* layout_object = GetLayoutBox()) int result = 0;
return AdjustForAbsoluteZoom::AdjustLayoutUnit( if (LayoutBox* layout_object = GetLayoutBox()) {
LayoutUnit( result = AdjustForAbsoluteZoom::AdjustLayoutUnit(
layout_object LayoutUnit(
->PixelSnappedClientHeightWithTableSpecialBehavior()), layout_object
layout_object->StyleRef()) ->PixelSnappedClientHeightWithTableSpecialBehavior()),
.Round(); layout_object->StyleRef())
return 0; .Round();
RecordScrollbarSizeForStudy(result, /* is_width= */ false,
/* is_offset= */ false);
}
return result;
} }
LayoutBox* Element::GetLayoutBoxForScrolling() const { LayoutBox* Element::GetLayoutBoxForScrolling() const {
......
...@@ -934,6 +934,10 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable { ...@@ -934,6 +934,10 @@ class CORE_EXPORT Element : public ContainerNode, public Animatable {
const ElementData* GetElementData() const { return element_data_.Get(); } const ElementData* GetElementData() const { return element_data_.Get(); }
UniqueElementData& EnsureUniqueElementData(); UniqueElementData& EnsureUniqueElementData();
void RecordScrollbarSizeForStudy(int measurement,
bool is_width,
bool is_offset);
void AddPropertyToPresentationAttributeStyle(MutableCSSPropertyValueSet*, void AddPropertyToPresentationAttributeStyle(MutableCSSPropertyValueSet*,
CSSPropertyID, CSSPropertyID,
CSSValueID identifier); CSSValueID identifier);
......
...@@ -26,8 +26,6 @@ ...@@ -26,8 +26,6 @@
#include "third_party/blink/renderer/core/html/html_element.h" #include "third_party/blink/renderer/core/html/html_element.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
#include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
#include "third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.h" #include "third_party/blink/renderer/bindings/core/v8/js_event_handler_for_content_attribute.h"
#include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_script.h" #include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_script.h"
#include "third_party/blink/renderer/bindings/core/v8/string_treat_null_as_empty_string_or_trusted_script.h" #include "third_party/blink/renderer/bindings/core/v8/string_treat_null_as_empty_string_or_trusted_script.h"
...@@ -1497,67 +1495,6 @@ int HTMLElement::offsetTopForBinding() { ...@@ -1497,67 +1495,6 @@ int HTMLElement::offsetTopForBinding() {
return 0; return 0;
} }
void HTMLElement::RecordScrollbarSizeForStudy(int offset_measurement,
bool is_width) {
if (!IdentifiabilityStudySettings::Get()->IsTypeAllowed(
IdentifiableSurface::Type::kScrollbarSize))
return;
// Check for presence of a scrollbar.
PaintLayerScrollableArea* area;
if (this == GetDocument().ScrollingElementNoLayout()) {
auto* view = GetDocument().View();
if (!view)
return;
area = view->LayoutViewport();
} else {
auto* layout = GetLayoutBox();
if (!layout)
return;
area = layout->GetScrollableArea();
}
if (!area || area->HasOverlayOverflowControls())
return;
Scrollbar* scrollbar =
is_width ? area->VerticalScrollbar() : area->HorizontalScrollbar();
// We intentionally exclude platform overlay scrollbars since their size
// cannot be detected in JavaScript using the methods below.
if (!scrollbar)
return;
IdentifiableSurface::ScrollbarSurface surface;
int scrollbar_size;
// There are two common ways to detect the size of a scrollbar in a DOM
// window. They are:
// 1. Compute the difference of the window.inner[Width|Height] and the
// corresponding document.scrollingElement.offset[Width|Height].
// 2. Any HTML element that insets the layout to fit a scrollbar, so it is
// measurable by a JavaScript program on a site.
if (this == GetDocument().scrollingElement()) {
LocalDOMWindow* dom_window = GetDocument().domWindow();
scrollbar_size =
(is_width ? dom_window->innerWidth() : dom_window->innerHeight()) -
offset_measurement;
surface = is_width
? IdentifiableSurface::ScrollbarSurface::kBodyOffsetWidth
: IdentifiableSurface::ScrollbarSurface::kBodyOffsetHeight;
} else {
scrollbar_size =
offset_measurement - (is_width ? clientWidth() : clientHeight());
surface = is_width
? IdentifiableSurface::ScrollbarSurface::kElemScrollbarWidth
: IdentifiableSurface::ScrollbarSurface::kElemScrollbarHeight;
}
blink::IdentifiabilityMetricBuilder(GetDocument().UkmSourceID())
.Set(blink::IdentifiableSurface::FromTypeAndToken(
blink::IdentifiableSurface::Type::kScrollbarSize, surface),
scrollbar_size)
.Record(GetDocument().UkmRecorder());
}
int HTMLElement::offsetWidthForBinding() { int HTMLElement::offsetWidthForBinding() {
GetDocument().EnsurePaintLocationDataValidForNode( GetDocument().EnsurePaintLocationDataValidForNode(
this, DocumentUpdateReason::kJavaScript); this, DocumentUpdateReason::kJavaScript);
...@@ -1569,7 +1506,8 @@ int HTMLElement::offsetWidthForBinding() { ...@@ -1569,7 +1506,8 @@ int HTMLElement::offsetWidthForBinding() {
LayoutUnit(layout_object->PixelSnappedOffsetWidth(offset_parent)), LayoutUnit(layout_object->PixelSnappedOffsetWidth(offset_parent)),
layout_object->StyleRef()) layout_object->StyleRef())
.Round(); .Round();
RecordScrollbarSizeForStudy(result, /* isWidth= */ true); RecordScrollbarSizeForStudy(result, /* isWidth= */ true,
/* is_offset= */ true);
} }
return result; return result;
} }
...@@ -1586,7 +1524,8 @@ int HTMLElement::offsetHeightForBinding() { ...@@ -1586,7 +1524,8 @@ int HTMLElement::offsetHeightForBinding() {
LayoutUnit(layout_object->PixelSnappedOffsetHeight(offset_parent)), LayoutUnit(layout_object->PixelSnappedOffsetHeight(offset_parent)),
layout_object->StyleRef()) layout_object->StyleRef())
.Round(); .Round();
RecordScrollbarSizeForStudy(result, /* isWidth= */ false); RecordScrollbarSizeForStudy(result, /* is_width= */ false,
/* is_offset= */ true);
} }
return result; return result;
} }
......
...@@ -212,8 +212,6 @@ class CORE_EXPORT HTMLElement : public Element { ...@@ -212,8 +212,6 @@ class CORE_EXPORT HTMLElement : public Element {
void HandleKeypressEvent(KeyboardEvent&); void HandleKeypressEvent(KeyboardEvent&);
void RecordScrollbarSizeForStudy(int, bool);
static AttributeTriggers* TriggersForAttributeName( static AttributeTriggers* TriggersForAttributeName(
const QualifiedName& attr_name); const QualifiedName& attr_name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment